]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.issues.common/src/org/simantics/issues/common/DependencyIssueSource2.java
b11fd220ddff588650af40c443d00c017336e9a8
[simantics/platform.git] / bundles / org.simantics.issues.common / src / org / simantics / issues / common / DependencyIssueSource2.java
1 package org.simantics.issues.common;
2
3 import java.util.ArrayList;
4 import java.util.HashSet;
5 import java.util.List;
6 import java.util.Set;
7 import java.util.concurrent.ConcurrentHashMap;
8 import java.util.concurrent.ConcurrentMap;
9 import java.util.concurrent.CopyOnWriteArraySet;
10
11 import org.simantics.Simantics;
12 import org.simantics.db.MetadataI;
13 import org.simantics.db.ReadGraph;
14 import org.simantics.db.Resource;
15 import org.simantics.db.WriteGraph;
16 import org.simantics.db.common.Indexing;
17 import org.simantics.db.common.changeset.GenericChangeListener;
18 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
19 import org.simantics.db.common.request.PossibleTypedParent;
20 import org.simantics.db.common.utils.Functions;
21 import org.simantics.db.common.utils.NameUtils;
22 import org.simantics.db.event.ChangeListener;
23 import org.simantics.db.exception.DatabaseException;
24 import org.simantics.db.layer0.genericrelation.DependenciesRelation.DependencyChangesRequest;
25 import org.simantics.db.layer0.genericrelation.DependencyChanges;
26 import org.simantics.db.service.GraphChangeListenerSupport;
27 import org.simantics.issues.ontology.IssueResource;
28 import org.simantics.layer0.Layer0;
29 import org.simantics.scl.runtime.function.Function2;
30 import org.simantics.simulation.ontology.SimulationResource;
31
32 public class DependencyIssueSource2 implements IssueSource {
33
34         public static final boolean DEBUG = false;
35         
36         private Resource source;
37         private Resource model;
38         private Resource type;
39         private Set<Resource> searchTypes;
40         private Resource base;
41         private Resource extensionFunction;
42
43         private CopyOnWriteArraySet<Function2<ReadGraph, List<Resource>, Boolean>> listeners = new CopyOnWriteArraySet<>();
44         private ConcurrentMap<Function2<ReadGraph, List<Resource>, Boolean>, ChangeListener> listenerMap = new ConcurrentHashMap<>();
45
46         public DependencyIssueSource2(ReadGraph graph, Resource source) throws DatabaseException {
47             Layer0 L0 = Layer0.getInstance(graph);
48                 IssueResource IR = IssueResource.getInstance(graph);
49                 this.source = source;
50                 this.model = graph.syncRequest(new PossibleTypedParent(source, SimulationResource.getInstance(graph).Model));
51                 this.extensionFunction = graph.getPossibleObject(source, IR.Sources_DependencyTracker_HasExtension); 
52                 this.type = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasType);
53                 HashSet<Resource> _searchTypes = new HashSet<>();
54                 _searchTypes.addAll(graph.getObjects(source, IR.Sources_DependencyTracker_HasSearchType));
55                 _searchTypes.add(type);
56                 this.searchTypes = new HashSet<>(_searchTypes);
57                 Resource baseFunction = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasBaseFunction);
58                 this.base = Functions.exec(graph, baseFunction, graph, graph.getSingleObject(source, L0.PartOf));
59         }
60
61         private List<Resource> resourcesToCheck(ReadGraph graph, DependencyChanges event) throws DatabaseException {
62
63                 HashSet<Resource> depSet = new HashSet<>();
64
65                 if(DEBUG) {
66                         System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] - component changes for type " + NameUtils.getSafeName(graph, searchTypes));
67                 }
68
69                 depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, model, base, searchTypes, event));
70                 depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, source, model, base, searchTypes));
71                 
72                 List<Resource> deps = new ArrayList<>(depSet);
73                 
74                 if(DEBUG) {
75                         System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] " + deps);
76                         for(Resource r : deps) {
77                                 System.err.println("dep " + NameUtils.getSafeName(graph, r));
78                         }
79                 }
80                 
81                 if(extensionFunction != null) {
82                         try {
83                                 deps = Functions.exec(graph, extensionFunction, graph, deps);
84                         } catch (Throwable t) {
85                                 t.printStackTrace();
86                         }
87                 }
88
89                 if(DEBUG) {
90                         for(Resource r : deps) {
91                                 System.err.println("dep extension " + NameUtils.getSafeName(graph, r));
92                         }
93                 }
94                 
95                 ArrayList<Resource> result = new ArrayList<>();
96                 for(Resource dep : deps) {
97                     // TODO: still not complete - e.g. someone can replace the InstanceOf
98                     Set<Resource> types = graph.getTypes(dep);
99                     if(types.isEmpty() || types.contains(type)) result.add(dep);
100                 }
101                 return result;
102                 
103         }
104
105     class DependencyChangeListener extends GenericChangeListener<DependencyChangesRequest, DependencyChanges> {
106
107         private boolean isValid(ReadGraph graph, List<Resource> toCheck) throws DatabaseException {
108             for(Resource resource : toCheck) {
109                 if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
110                     return false;
111                 }
112             }
113             return true;
114         }
115
116         @Override
117         public boolean preEventRequest() {
118             return !Indexing.isDependenciesIndexingDisabled();
119         }
120
121         @Override
122         public void onEvent(ReadGraph graph, MetadataI metadata, DependencyChanges event) throws DatabaseException {
123
124             List<Resource> toCheck = resourcesToCheck(graph, event);
125             if(!isValid(graph, toCheck)) {
126                 for(Function2<ReadGraph, List<Resource>, Boolean> r : listeners) {
127                     r.apply(graph, toCheck);
128                 }
129             }
130
131             if(graph instanceof WriteGraph) {
132                 IssueSourceUtils.update((WriteGraph)graph, source);
133             }
134         }
135
136     }
137
138     @Override
139     public void addDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
140         boolean added = listeners.add(runnable);
141         if (added) {
142             GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
143             ChangeListener metadataListener = new DependencyChangeListener();
144             listenerMap.put(runnable, metadataListener);
145             changeSupport.addMetadataListener(metadataListener);
146         }
147     }
148
149     @Override
150     public void removeDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
151         boolean removed = listeners.remove(runnable);
152         ChangeListener metadataListener = listenerMap.remove(runnable);
153         if (removed && metadataListener != null) {
154             GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
155             changeSupport.removeMetadataListener(metadataListener);
156         }
157     }
158
159         @Override
160         public void update(WriteGraph graph, List<Resource> resources) throws DatabaseException {
161
162                 for(Resource resource : resources) {
163                         if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
164                                 new DependencyIssueSynchronizer2(resource, source).perform(graph);
165                         }
166                 }
167
168                 IssueSourceUtils.update(graph, source);
169
170         }
171
172         @Override
173         public boolean needUpdate(ReadGraph graph, List<Resource> resources) throws DatabaseException {
174
175                 for(Resource resource : resources) {
176                         if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) return true;
177                 }
178
179                 return false;
180
181         }
182
183 }