1 package org.simantics.issues.common;
\r
3 import java.util.ArrayList;
\r
4 import java.util.HashSet;
\r
5 import java.util.List;
\r
6 import java.util.Set;
\r
7 import java.util.concurrent.ConcurrentHashMap;
\r
8 import java.util.concurrent.ConcurrentMap;
\r
9 import java.util.concurrent.CopyOnWriteArraySet;
\r
11 import org.simantics.Simantics;
\r
12 import org.simantics.db.MetadataI;
\r
13 import org.simantics.db.ReadGraph;
\r
14 import org.simantics.db.Resource;
\r
15 import org.simantics.db.WriteGraph;
\r
16 import org.simantics.db.common.Indexing;
\r
17 import org.simantics.db.common.changeset.GenericChangeListener;
\r
18 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
\r
19 import org.simantics.db.common.request.PossibleTypedParent;
\r
20 import org.simantics.db.common.utils.Functions;
\r
21 import org.simantics.db.common.utils.NameUtils;
\r
22 import org.simantics.db.event.ChangeListener;
\r
23 import org.simantics.db.exception.DatabaseException;
\r
24 import org.simantics.db.layer0.genericrelation.DependenciesRelation.DependencyChangesRequest;
\r
25 import org.simantics.db.layer0.genericrelation.DependencyChanges;
\r
26 import org.simantics.db.service.GraphChangeListenerSupport;
\r
27 import org.simantics.issues.ontology.IssueResource;
\r
28 import org.simantics.layer0.Layer0;
\r
29 import org.simantics.scl.runtime.function.Function2;
\r
30 import org.simantics.simulation.ontology.SimulationResource;
\r
32 public class DependencyIssueSource2 implements IssueSource {
\r
34 public static final boolean DEBUG = false;
\r
36 private Resource source;
\r
37 private Resource model;
\r
38 private Resource type;
\r
39 private Set<Resource> searchTypes;
\r
40 private Resource base;
\r
41 private Resource extensionFunction;
\r
43 private CopyOnWriteArraySet<Function2<ReadGraph, List<Resource>, Boolean>> listeners = new CopyOnWriteArraySet<>();
\r
44 private ConcurrentMap<Function2<ReadGraph, List<Resource>, Boolean>, ChangeListener> listenerMap = new ConcurrentHashMap<>();
\r
46 public DependencyIssueSource2(ReadGraph graph, Resource source) throws DatabaseException {
\r
47 Layer0 L0 = Layer0.getInstance(graph);
\r
48 IssueResource IR = IssueResource.getInstance(graph);
\r
49 this.source = source;
\r
50 this.model = graph.syncRequest(new PossibleTypedParent(source, SimulationResource.getInstance(graph).Model));
\r
51 this.extensionFunction = graph.getPossibleObject(source, IR.Sources_DependencyTracker_HasExtension);
\r
52 this.type = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasType);
\r
53 HashSet<Resource> _searchTypes = new HashSet<>();
\r
54 _searchTypes.addAll(graph.getObjects(source, IR.Sources_DependencyTracker_HasSearchType));
\r
55 _searchTypes.add(type);
\r
56 this.searchTypes = new HashSet<>(_searchTypes);
\r
57 Resource baseFunction = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasBaseFunction);
\r
58 this.base = Functions.exec(graph, baseFunction, graph, graph.getSingleObject(source, L0.PartOf));
\r
61 private List<Resource> resourcesToCheck(ReadGraph graph, DependencyChanges event) throws DatabaseException {
\r
63 HashSet<Resource> depSet = new HashSet<>();
\r
66 System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] - component changes for type " + NameUtils.getSafeName(graph, searchTypes));
\r
69 depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, model, base, searchTypes, event));
\r
70 depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, source, model, base, searchTypes));
\r
72 List<Resource> deps = new ArrayList<>(depSet);
\r
75 System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] " + deps);
\r
76 for(Resource r : deps) {
\r
77 System.err.println("dep " + NameUtils.getSafeName(graph, r));
\r
81 if(extensionFunction != null) {
\r
83 deps = Functions.exec(graph, extensionFunction, graph, deps);
\r
84 } catch (Throwable t) {
\r
85 t.printStackTrace();
\r
90 for(Resource r : deps) {
\r
91 System.err.println("dep extension " + NameUtils.getSafeName(graph, r));
\r
95 ArrayList<Resource> result = new ArrayList<>();
\r
96 for(Resource dep : deps) {
\r
97 // TODO: still not complete - e.g. someone can replace the InstanceOf
\r
98 Set<Resource> types = graph.getTypes(dep);
\r
99 if(types.isEmpty() || types.contains(type)) result.add(dep);
\r
105 class DependencyChangeListener extends GenericChangeListener<DependencyChangesRequest, DependencyChanges> {
\r
107 private boolean isValid(ReadGraph graph, List<Resource> toCheck) throws DatabaseException {
\r
108 for(Resource resource : toCheck) {
\r
109 if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
\r
117 public boolean preEventRequest() {
\r
118 return !Indexing.isDependenciesIndexingDisabled();
\r
122 public void onEvent(ReadGraph graph, MetadataI metadata, DependencyChanges event) throws DatabaseException {
\r
124 List<Resource> toCheck = resourcesToCheck(graph, event);
\r
125 if(!isValid(graph, toCheck)) {
\r
126 for(Function2<ReadGraph, List<Resource>, Boolean> r : listeners) {
\r
127 r.apply(graph, toCheck);
\r
131 if(graph instanceof WriteGraph) {
\r
132 IssueSourceUtils.update((WriteGraph)graph, source);
\r
139 public void addDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
\r
140 boolean added = listeners.add(runnable);
\r
142 GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
\r
143 ChangeListener metadataListener = new DependencyChangeListener();
\r
144 listenerMap.put(runnable, metadataListener);
\r
145 changeSupport.addMetadataListener(metadataListener);
\r
150 public void removeDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
\r
151 boolean removed = listeners.remove(runnable);
\r
152 ChangeListener metadataListener = listenerMap.remove(runnable);
\r
153 if (removed && metadataListener != null) {
\r
154 GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
\r
155 changeSupport.removeMetadataListener(metadataListener);
\r
160 public void update(WriteGraph graph, List<Resource> resources) throws DatabaseException {
\r
162 for(Resource resource : resources) {
\r
163 if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
\r
164 new DependencyIssueSynchronizer2(resource, source).perform(graph);
\r
168 IssueSourceUtils.update(graph, source);
\r
173 public boolean needUpdate(ReadGraph graph, List<Resource> resources) throws DatabaseException {
\r
175 for(Resource resource : resources) {
\r
176 if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) return true;
\r