]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/client/StructuralChangeFlattener.java
Separate DB and non-DB code to different structural sync bundles
[simantics/platform.git] / bundles / org.simantics.structural.synchronization.client / src / org / simantics / structural / synchronization / client / StructuralChangeFlattener.java
diff --git a/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/client/StructuralChangeFlattener.java b/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/client/StructuralChangeFlattener.java
new file mode 100644 (file)
index 0000000..4503a82
--- /dev/null
@@ -0,0 +1,128 @@
+package org.simantics.structural.synchronization.client;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.genericrelation.DependencyChanges;
+import org.simantics.db.layer0.request.ModelInstances;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.layer0.Layer0;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.structural2.utils.StructuralChangeVisitor;
+import org.simantics.structural2.utils.StructuralMetadataUtils;
+
+/**
+ * Browses change metadata from the requested revision and
+ * marks the components in a flat structural configuration
+ * where changes have been occured.
+ * 
+ * @author Hannu Niemistö
+ */
+public class StructuralChangeFlattener {
+    
+    private static Variable[] EMPTY_VARIABLE_ARRAY = new Variable[0];
+    
+    public static TObjectIntHashMap<Variable> getModifiedComponents(ReadGraph graph,
+            Variable rootVariable, long fromRevision) throws DatabaseException {
+        Visitor visitor = new Visitor(graph, rootVariable);
+        StructuralMetadataUtils.visitStructuralChangesFrom(graph,
+                Variables.getModel(graph, rootVariable),
+                fromRevision, visitor);
+        return visitor.modifiedComponents;
+    }
+
+    public static TObjectIntHashMap<Variable> getModifiedComponents(ReadGraph graph,
+            Variable rootVariable, DependencyChanges.Change[] changes) throws DatabaseException {
+        Visitor visitor = new Visitor(graph, rootVariable);
+        StructuralMetadataUtils.visitStructuralChangesFrom(graph,
+                Variables.getModel(graph, rootVariable),
+                changes, visitor);
+        return visitor.modifiedComponents;
+    }
+
+    private static class Visitor implements StructuralChangeVisitor {
+
+        Variable rootVariable;
+        Resource rootResource;
+        Resource model;
+        THashMap<Resource, Variable[]> visitedVariables = new THashMap<Resource, Variable[]>();
+        Layer0 L0;
+        StructuralResource2 STR;
+        TObjectIntHashMap<Variable> modifiedComponents = new TObjectIntHashMap<Variable>(); 
+        
+        public Visitor(ReadGraph graph, Variable rootVariable) throws DatabaseException {
+            this.rootVariable = rootVariable;
+            this.rootResource = rootVariable.getRepresents(graph);
+            this.model = Variables.getModel(graph, rootVariable);
+            this.L0 = Layer0.getInstance(graph);
+            this.STR = StructuralResource2.getInstance(graph);
+        }
+        
+        @Override
+        public void visitComponentChange(ReadGraph graph, Resource component, boolean componentItselfModified)
+                throws DatabaseException {
+            Variable[] variables = visitedVariables.get(component);
+            if(variables == null) {
+                variables = visitUnseenComponent(graph, component);
+                visitedVariables.put(component, variables);
+            }
+            if(componentItselfModified)
+                for(Variable variable : variables)
+                    modifiedComponents.put(variable, 2);
+            else
+                for(Variable variable : variables)
+                    modifiedComponents.putIfAbsent(variable, 1);
+        }
+        
+        private Variable[] visitUnseenComponent(ReadGraph graph, Resource component) throws DatabaseException {
+            // Is root?
+            if(component.equals(rootResource))
+                return new Variable[] { rootVariable };
+            
+            // Check if this a component type root
+            Resource componentType = graph.getPossibleObject(component, STR.Defines);
+            if(componentType != null) {
+                ArrayList<Variable> result = new ArrayList<Variable>();
+                Map<String,Resource> instances = graph.syncRequest(new ModelInstances(model, componentType), TransientCacheAsyncListener.<Map<String,Resource>>instance());
+                for(Resource instance : instances.values()) {
+                    visitComponentChange(graph, instance, false);
+                    for(Variable variable : visitedVariables.get(instance))
+                        result.add(variable);
+                }
+                if(result.isEmpty())
+                    return EMPTY_VARIABLE_ARRAY;
+                else
+                    return result.toArray(new Variable[result.size()]);
+            }
+            
+            // Check parent
+            Resource parent = graph.getPossibleObject(component, L0.PartOf);
+            String name = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);
+            if(parent == null || name == null || !graph.isInstanceOf(component, STR.Component))
+                return EMPTY_VARIABLE_ARRAY;
+            
+            visitComponentChange(graph, parent, false);
+            Variable[] parentCorrespondences = visitedVariables.get(parent);
+            ArrayList<Variable> result = new ArrayList<Variable>(parentCorrespondences.length);
+            for(Variable parentCorrespondence : parentCorrespondences) {
+                Variable correspondence = parentCorrespondence.getPossibleChild(graph, name);
+                if(correspondence != null)
+                    result.add(correspondence);
+            }
+            if(result.isEmpty())
+                return EMPTY_VARIABLE_ARRAY;
+            else
+                return result.toArray(new Variable[result.size()]);
+        }
+        
+    }
+}