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