--- /dev/null
+package org.simantics.db.layer0.genericrelation;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
+import org.simantics.db.common.request.IndexRoots;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.genericrelation.DependencyChanges.Change;\r
+import org.simantics.db.layer0.genericrelation.DependencyChanges.ChangeType;\r
+import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentAddition;\r
+import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentModification;\r
+import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentRemoval;\r
+import org.simantics.db.layer0.genericrelation.DependencyChanges.LinkChange;\r
+import org.simantics.db.service.CollectionSupport;\r
+import org.simantics.layer0.Layer0;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+public class DependencyChangesWriter {\r
+ ReadGraph g;\r
+ Layer0 l0;\r
+\r
+ THashMap<Resource, Change> changesByResource = new THashMap<>();\r
+ ArrayList<ComponentRemoval> removals = new ArrayList<>();\r
+\r
+ public DependencyChangesWriter(ReadGraph g) {\r
+ this.g = g;\r
+ this.l0 = Layer0.getInstance(g);\r
+ }\r
+\r
+ public void addComponentModification(Resource component) throws DatabaseException {\r
+ if (!component.isPersistent())\r
+ return;\r
+ if(!changesByResource.contains(component))\r
+ changesByResource.put(component, new ComponentModification(component));\r
+ }\r
+\r
+ public void addLinkChange(Resource component) throws DatabaseException {\r
+ if (!component.isPersistent())\r
+ return;\r
+ //if(!changesByResource.contains(component))\r
+ changesByResource.put(component, new LinkChange(component));\r
+ }\r
+\r
+ public void addComponentAddition(Resource parent, Resource component) throws DatabaseException {\r
+ if (!component.isPersistent())\r
+ return;\r
+ changesByResource.put(component, new ComponentAddition(component, parent));\r
+ }\r
+\r
+ public void addComponentRemoval(Resource parent, Resource component) throws DatabaseException {\r
+// System.err.println("addComponentRemoval " + component);\r
+ // NOTE: removals are registered by their parent resource because the\r
+ // (component, PartOf, parent) link no longer exists and the model cannot\r
+ // be found otherwise.\r
+// changesByResource.put(parent, new ComponentRemoval(component, parent));\r
+ if (!component.isPersistent())\r
+ return;\r
+ removals.add(new ComponentRemoval(component, parent));\r
+ }\r
+\r
+ public DependencyChanges getResult() throws DatabaseException {\r
+ THashMap<Resource, ArrayList<Change>> changes = new THashMap<>();\r
+ CollectionSupport cs = g.getService(CollectionSupport.class);\r
+ List<Resource> keys = cs.asSortedList(changesByResource.keySet());\r
+ boolean hasUnresolved = false;\r
+ for(Resource key : keys) {\r
+ Change change = changesByResource.get(key);\r
+ // Default logic with simpler index root resolution.\r
+ Resource model = g.syncRequest(new PossibleIndexRoot(key), TransientCacheListener.<Resource>instance());\r
+ boolean modelFound = model != null;\r
+ if (model != null) {\r
+ addChange(model, change, changes);\r
+ } else {\r
+ // Very heavy fallback logic\r
+ Collection<Resource> models = g.syncRequest(new IndexRoots(key), TransientCacheListener.<Collection<Resource>>instance());\r
+ for(Resource m : models)\r
+ addChange(m, change, changes);\r
+ modelFound = !models.isEmpty();\r
+ }\r
+ if (modelFound && change.getType() == ChangeType.COMPONENT_ADDITION) {\r
+ hasUnresolved = true;\r
+ }\r
+ }\r
+ if (!removals.isEmpty()) {\r
+ THashMap<Resource, ComponentRemoval> removedComponents = new THashMap<>(removals.size());\r
+ for(ComponentRemoval removal : removals)\r
+ removedComponents.put(removal.component, removal);\r
+ for(ComponentRemoval removal : removals) {\r
+ Resource parent = removal.parent;\r
+ Collection<Resource> models = getModelsForRemoved(g, parent, removedComponents); \r
+ for(Resource model : models) {\r
+ ArrayList<Change> modelChanges = changes.get(model);\r
+ if(modelChanges == null) {\r
+ modelChanges = new ArrayList<>();\r
+ changes.put(model, modelChanges);\r
+ }\r
+ modelChanges.add(removal);\r
+ }\r
+ if(models.isEmpty() && !removedComponents.contains(parent)) {\r
+ hasUnresolved = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ return new DependencyChanges(changes, hasUnresolved);\r
+ }\r
+\r
+ private void addChange(Resource model, Change change, Map<Resource, ArrayList<Change>> changes) {\r
+ ArrayList<Change> modelChanges = changes.get(model);\r
+ if(modelChanges == null) {\r
+ modelChanges = new ArrayList<>();\r
+ changes.put(model, modelChanges);\r
+ }\r
+ modelChanges.add(change);\r
+ }\r
+\r
+ private Collection<Resource> getModelsForRemoved(ReadGraph graph, Resource resource, THashMap<Resource, ComponentRemoval> removedComponents) throws DatabaseException {\r
+ ComponentRemoval removal = removedComponents.get(resource);\r
+ if(removal == null) {\r
+ Resource model = g.syncRequest(new PossibleIndexRoot(resource), TransientCacheListener.<Resource>instance());\r
+ if (model != null)\r
+ return Collections.singleton(model);\r
+ return graph.syncRequest(new IndexRoots(resource), TransientCacheListener.<Collection<Resource>>instance());\r
+ }\r
+ return getModelsForRemoved(graph, removal.parent, removedComponents);\r
+ }\r
+ \r
+}\r