1 package org.simantics.issues.common;
3 import java.util.ArrayList;
4 import java.util.HashSet;
7 import java.util.concurrent.ConcurrentHashMap;
8 import java.util.concurrent.ConcurrentMap;
9 import java.util.concurrent.CopyOnWriteArraySet;
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;
32 public class DependencyIssueSource2 implements IssueSource {
34 public static final boolean DEBUG = false;
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;
43 private CopyOnWriteArraySet<Function2<ReadGraph, List<Resource>, Boolean>> listeners = new CopyOnWriteArraySet<>();
44 private ConcurrentMap<Function2<ReadGraph, List<Resource>, Boolean>, ChangeListener> listenerMap = new ConcurrentHashMap<>();
46 public DependencyIssueSource2(ReadGraph graph, Resource source) throws DatabaseException {
47 Layer0 L0 = Layer0.getInstance(graph);
48 IssueResource IR = IssueResource.getInstance(graph);
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));
61 private List<Resource> resourcesToCheck(ReadGraph graph, DependencyChanges event) throws DatabaseException {
63 HashSet<Resource> depSet = new HashSet<>();
66 System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] - component changes for type " + NameUtils.getSafeName(graph, searchTypes));
69 depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, model, base, searchTypes, event));
70 depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, source, model, base, searchTypes));
72 List<Resource> deps = new ArrayList<>(depSet);
75 System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] " + deps);
76 for(Resource r : deps) {
77 System.err.println("dep " + NameUtils.getSafeName(graph, r));
81 if(extensionFunction != null) {
83 deps = Functions.exec(graph, extensionFunction, graph, deps);
84 } catch (Throwable t) {
90 for(Resource r : deps) {
91 System.err.println("dep extension " + NameUtils.getSafeName(graph, r));
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);
105 class DependencyChangeListener extends GenericChangeListener<DependencyChangesRequest, DependencyChanges> {
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())) {
117 public boolean preEventRequest() {
118 return !Indexing.isDependenciesIndexingDisabled();
122 public void onEvent(ReadGraph graph, MetadataI metadata, DependencyChanges event) throws DatabaseException {
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);
131 if(graph instanceof WriteGraph) {
132 IssueSourceUtils.update((WriteGraph)graph, source);
139 public void addDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
140 boolean added = listeners.add(runnable);
142 GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
143 ChangeListener metadataListener = new DependencyChangeListener();
144 listenerMap.put(runnable, metadataListener);
145 changeSupport.addMetadataListener(metadataListener);
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);
160 public void update(WriteGraph graph, List<Resource> resources) throws DatabaseException {
162 for(Resource resource : resources) {
163 if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
164 new DependencyIssueSynchronizer2(resource, source).perform(graph);
168 IssueSourceUtils.update(graph, source);
173 public boolean needUpdate(ReadGraph graph, List<Resource> resources) throws DatabaseException {
175 for(Resource resource : resources) {
176 if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) return true;