-package org.simantics.issues.common;\r
-\r
-import java.util.ArrayList;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.concurrent.ConcurrentHashMap;\r
-import java.util.concurrent.ConcurrentMap;\r
-import java.util.concurrent.CopyOnWriteArraySet;\r
-\r
-import org.simantics.Simantics;\r
-import org.simantics.db.MetadataI;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.Indexing;\r
-import org.simantics.db.common.changeset.GenericChangeListener;\r
-import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
-import org.simantics.db.common.request.PossibleTypedParent;\r
-import org.simantics.db.common.utils.Functions;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.event.ChangeListener;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.genericrelation.DependenciesRelation.DependencyChangesRequest;\r
-import org.simantics.db.layer0.genericrelation.DependencyChanges;\r
-import org.simantics.db.service.GraphChangeListenerSupport;\r
-import org.simantics.issues.ontology.IssueResource;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.scl.runtime.function.Function2;\r
-import org.simantics.simulation.ontology.SimulationResource;\r
-\r
-public class DependencyIssueSource2 implements IssueSource {\r
-\r
- public static final boolean DEBUG = false;\r
- \r
- private Resource source;\r
- private Resource model;\r
- private Resource type;\r
- private Set<Resource> searchTypes;\r
- private Resource base;\r
- private Resource extensionFunction;\r
-\r
- private CopyOnWriteArraySet<Function2<ReadGraph, List<Resource>, Boolean>> listeners = new CopyOnWriteArraySet<>();\r
- private ConcurrentMap<Function2<ReadGraph, List<Resource>, Boolean>, ChangeListener> listenerMap = new ConcurrentHashMap<>();\r
-\r
- public DependencyIssueSource2(ReadGraph graph, Resource source) throws DatabaseException {\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- IssueResource IR = IssueResource.getInstance(graph);\r
- this.source = source;\r
- this.model = graph.syncRequest(new PossibleTypedParent(source, SimulationResource.getInstance(graph).Model));\r
- this.extensionFunction = graph.getPossibleObject(source, IR.Sources_DependencyTracker_HasExtension); \r
- this.type = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasType);\r
- HashSet<Resource> _searchTypes = new HashSet<>();\r
- _searchTypes.addAll(graph.getObjects(source, IR.Sources_DependencyTracker_HasSearchType));\r
- _searchTypes.add(type);\r
- this.searchTypes = new HashSet<>(_searchTypes);\r
- Resource baseFunction = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasBaseFunction);\r
- this.base = Functions.exec(graph, baseFunction, graph, graph.getSingleObject(source, L0.PartOf));\r
- }\r
-\r
- private List<Resource> resourcesToCheck(ReadGraph graph, DependencyChanges event) throws DatabaseException {\r
-\r
- HashSet<Resource> depSet = new HashSet<>();\r
-\r
- if(DEBUG) {\r
- System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] - component changes for type " + NameUtils.getSafeName(graph, searchTypes));\r
- }\r
-\r
- depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, model, base, searchTypes, event));\r
- depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, source, model, base, searchTypes));\r
- \r
- List<Resource> deps = new ArrayList<>(depSet);\r
- \r
- if(DEBUG) {\r
- System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] " + deps);\r
- for(Resource r : deps) {\r
- System.err.println("dep " + NameUtils.getSafeName(graph, r));\r
- }\r
- }\r
- \r
- if(extensionFunction != null) {\r
- try {\r
- deps = Functions.exec(graph, extensionFunction, graph, deps);\r
- } catch (Throwable t) {\r
- t.printStackTrace();\r
- }\r
- }\r
-\r
- if(DEBUG) {\r
- for(Resource r : deps) {\r
- System.err.println("dep extension " + NameUtils.getSafeName(graph, r));\r
- }\r
- }\r
- \r
- ArrayList<Resource> result = new ArrayList<>();\r
- for(Resource dep : deps) {\r
- // TODO: still not complete - e.g. someone can replace the InstanceOf\r
- Set<Resource> types = graph.getTypes(dep);\r
- if(types.isEmpty() || types.contains(type)) result.add(dep);\r
- }\r
- return result;\r
- \r
- }\r
-\r
- class DependencyChangeListener extends GenericChangeListener<DependencyChangesRequest, DependencyChanges> {\r
-\r
- private boolean isValid(ReadGraph graph, List<Resource> toCheck) throws DatabaseException {\r
- for(Resource resource : toCheck) {\r
- if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {\r
- return false;\r
- }\r
- }\r
- return true;\r
- }\r
-\r
- @Override\r
- public boolean preEventRequest() {\r
- return !Indexing.isDependenciesIndexingDisabled();\r
- }\r
-\r
- @Override\r
- public void onEvent(ReadGraph graph, MetadataI metadata, DependencyChanges event) throws DatabaseException {\r
-\r
- List<Resource> toCheck = resourcesToCheck(graph, event);\r
- if(!isValid(graph, toCheck)) {\r
- for(Function2<ReadGraph, List<Resource>, Boolean> r : listeners) {\r
- r.apply(graph, toCheck);\r
- }\r
- }\r
-\r
- if(graph instanceof WriteGraph) {\r
- IssueSourceUtils.update((WriteGraph)graph, source);\r
- }\r
- }\r
-\r
- }\r
-\r
- @Override\r
- public void addDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {\r
- boolean added = listeners.add(runnable);\r
- if (added) {\r
- GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);\r
- ChangeListener metadataListener = new DependencyChangeListener();\r
- listenerMap.put(runnable, metadataListener);\r
- changeSupport.addMetadataListener(metadataListener);\r
- }\r
- }\r
-\r
- @Override\r
- public void removeDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {\r
- boolean removed = listeners.remove(runnable);\r
- ChangeListener metadataListener = listenerMap.remove(runnable);\r
- if (removed && metadataListener != null) {\r
- GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);\r
- changeSupport.removeMetadataListener(metadataListener);\r
- }\r
- }\r
-\r
- @Override\r
- public void update(WriteGraph graph, List<Resource> resources) throws DatabaseException {\r
-\r
- for(Resource resource : resources) {\r
- if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {\r
- new DependencyIssueSynchronizer2(resource, source).perform(graph);\r
- }\r
- }\r
-\r
- IssueSourceUtils.update(graph, source);\r
-\r
- }\r
-\r
- @Override\r
- public boolean needUpdate(ReadGraph graph, List<Resource> resources) throws DatabaseException {\r
-\r
- for(Resource resource : resources) {\r
- if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) return true;\r
- }\r
-\r
- return false;\r
-\r
- }\r
-\r
-}\r
+package org.simantics.issues.common;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.simantics.Simantics;
+import org.simantics.db.MetadataI;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.Indexing;
+import org.simantics.db.common.changeset.GenericChangeListener;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.PossibleTypedParent;
+import org.simantics.db.common.utils.Functions;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.event.ChangeListener;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.genericrelation.DependenciesRelation.DependencyChangesRequest;
+import org.simantics.db.layer0.genericrelation.DependencyChanges;
+import org.simantics.db.service.GraphChangeListenerSupport;
+import org.simantics.issues.ontology.IssueResource;
+import org.simantics.layer0.Layer0;
+import org.simantics.scl.runtime.function.Function2;
+import org.simantics.simulation.ontology.SimulationResource;
+
+public class DependencyIssueSource2 implements IssueSource {
+
+ public static final boolean DEBUG = false;
+
+ private Resource source;
+ private Resource model;
+ private Resource type;
+ private Set<Resource> searchTypes;
+ private Resource base;
+ private Resource extensionFunction;
+
+ private CopyOnWriteArraySet<Function2<ReadGraph, List<Resource>, Boolean>> listeners = new CopyOnWriteArraySet<>();
+ private ConcurrentMap<Function2<ReadGraph, List<Resource>, Boolean>, ChangeListener> listenerMap = new ConcurrentHashMap<>();
+
+ public DependencyIssueSource2(ReadGraph graph, Resource source) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ IssueResource IR = IssueResource.getInstance(graph);
+ this.source = source;
+ this.model = graph.syncRequest(new PossibleTypedParent(source, SimulationResource.getInstance(graph).Model));
+ this.extensionFunction = graph.getPossibleObject(source, IR.Sources_DependencyTracker_HasExtension);
+ this.type = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasType);
+ HashSet<Resource> _searchTypes = new HashSet<>();
+ _searchTypes.addAll(graph.getObjects(source, IR.Sources_DependencyTracker_HasSearchType));
+ _searchTypes.add(type);
+ this.searchTypes = new HashSet<>(_searchTypes);
+ Resource baseFunction = graph.getSingleObject(source, IR.Sources_DependencyTracker_HasBaseFunction);
+ this.base = Functions.exec(graph, baseFunction, graph, graph.getSingleObject(source, L0.PartOf));
+ }
+
+ private List<Resource> resourcesToCheck(ReadGraph graph, DependencyChanges event) throws DatabaseException {
+
+ HashSet<Resource> depSet = new HashSet<>();
+
+ if(DEBUG) {
+ System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] - component changes for type " + NameUtils.getSafeName(graph, searchTypes));
+ }
+
+ depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, model, base, searchTypes, event));
+ depSet.addAll(IssueSourceUtils.getChangedDependencies(graph, source, model, base, searchTypes));
+
+ List<Resource> deps = new ArrayList<>(depSet);
+
+ if(DEBUG) {
+ System.err.println("resourcesToCheck[" + NameUtils.getSafeName(graph, source) + "] " + deps);
+ for(Resource r : deps) {
+ System.err.println("dep " + NameUtils.getSafeName(graph, r));
+ }
+ }
+
+ if(extensionFunction != null) {
+ try {
+ deps = Functions.exec(graph, extensionFunction, graph, deps);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ if(DEBUG) {
+ for(Resource r : deps) {
+ System.err.println("dep extension " + NameUtils.getSafeName(graph, r));
+ }
+ }
+
+ ArrayList<Resource> result = new ArrayList<>();
+ for(Resource dep : deps) {
+ // TODO: still not complete - e.g. someone can replace the InstanceOf
+ Set<Resource> types = graph.getTypes(dep);
+ if(types.isEmpty() || types.contains(type)) result.add(dep);
+ }
+ return result;
+
+ }
+
+ class DependencyChangeListener extends GenericChangeListener<DependencyChangesRequest, DependencyChanges> {
+
+ private boolean isValid(ReadGraph graph, List<Resource> toCheck) throws DatabaseException {
+ for(Resource resource : toCheck) {
+ if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean preEventRequest() {
+ return !Indexing.isDependenciesIndexingDisabled();
+ }
+
+ @Override
+ public void onEvent(ReadGraph graph, MetadataI metadata, DependencyChanges event) throws DatabaseException {
+
+ List<Resource> toCheck = resourcesToCheck(graph, event);
+ if(!isValid(graph, toCheck)) {
+ for(Function2<ReadGraph, List<Resource>, Boolean> r : listeners) {
+ r.apply(graph, toCheck);
+ }
+ }
+
+ if(graph instanceof WriteGraph) {
+ IssueSourceUtils.update((WriteGraph)graph, source);
+ }
+ }
+
+ }
+
+ @Override
+ public void addDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
+ boolean added = listeners.add(runnable);
+ if (added) {
+ GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
+ ChangeListener metadataListener = new DependencyChangeListener();
+ listenerMap.put(runnable, metadataListener);
+ changeSupport.addMetadataListener(metadataListener);
+ }
+ }
+
+ @Override
+ public void removeDirtyListener(Function2<ReadGraph, List<Resource>, Boolean> runnable) {
+ boolean removed = listeners.remove(runnable);
+ ChangeListener metadataListener = listenerMap.remove(runnable);
+ if (removed && metadataListener != null) {
+ GraphChangeListenerSupport changeSupport = Simantics.getSession().getService(GraphChangeListenerSupport.class);
+ changeSupport.removeMetadataListener(metadataListener);
+ }
+ }
+
+ @Override
+ public void update(WriteGraph graph, List<Resource> resources) throws DatabaseException {
+
+ for(Resource resource : resources) {
+ if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) {
+ new DependencyIssueSynchronizer2(resource, source).perform(graph);
+ }
+ }
+
+ IssueSourceUtils.update(graph, source);
+
+ }
+
+ @Override
+ public boolean needUpdate(ReadGraph graph, List<Resource> resources) throws DatabaseException {
+
+ for(Resource resource : resources) {
+ if(!graph.syncRequest(new DependencyIssueValidator2(resource, model, source), TransientCacheListener.<Boolean>instance())) return true;
+ }
+
+ return false;
+
+ }
+
+}