]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/StructuralChangeFlattener.java
2809c5836687ece9306b5254808f72b829c6e9bd
[simantics/platform.git] / bundles / org.simantics.structural.synchronization.client / src / org / simantics / structural / synchronization / StructuralChangeFlattener.java
1 package org.simantics.structural.synchronization;
2
3 import gnu.trove.map.hash.THashMap;
4 import gnu.trove.map.hash.TObjectIntHashMap;
5
6 import java.util.ArrayList;
7 import java.util.Map;
8
9 import org.simantics.databoard.Bindings;
10 import org.simantics.db.ReadGraph;
11 import org.simantics.db.Resource;
12 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
13 import org.simantics.db.exception.DatabaseException;
14 import org.simantics.db.layer0.genericrelation.DependencyChanges;
15 import org.simantics.db.layer0.request.ModelInstances;
16 import org.simantics.db.layer0.variable.Variable;
17 import org.simantics.db.layer0.variable.Variables;
18 import org.simantics.layer0.Layer0;
19 import org.simantics.structural.stubs.StructuralResource2;
20 import org.simantics.structural2.utils.StructuralChangeVisitor;
21 import org.simantics.structural2.utils.StructuralMetadataUtils;
22
23 /**
24  * Browses change metadata from the requested revision and
25  * marks the components in a flat structural configuration
26  * where changes have been occured.
27  * 
28  * @author Hannu Niemistö
29  */
30 public class StructuralChangeFlattener {
31     
32     private static Variable[] EMPTY_VARIABLE_ARRAY = new Variable[0];
33     
34     public static TObjectIntHashMap<Variable> getModifiedComponents(ReadGraph graph,
35             Variable rootVariable, long fromRevision) throws DatabaseException {
36         Visitor visitor = new Visitor(graph, rootVariable);
37         StructuralMetadataUtils.visitStructuralChangesFrom(graph,
38                 Variables.getModel(graph, rootVariable),
39                 fromRevision, visitor);
40         return visitor.modifiedComponents;
41     }
42
43     public static TObjectIntHashMap<Variable> getModifiedComponents(ReadGraph graph,
44             Variable rootVariable, DependencyChanges.Change[] changes) throws DatabaseException {
45         Visitor visitor = new Visitor(graph, rootVariable);
46         StructuralMetadataUtils.visitStructuralChangesFrom(graph,
47                 Variables.getModel(graph, rootVariable),
48                 changes, visitor);
49         return visitor.modifiedComponents;
50     }
51
52     private static class Visitor implements StructuralChangeVisitor {
53
54         Variable rootVariable;
55         Resource rootResource;
56         Resource model;
57         THashMap<Resource, Variable[]> visitedVariables = new THashMap<Resource, Variable[]>();
58         Layer0 L0;
59         StructuralResource2 STR;
60         TObjectIntHashMap<Variable> modifiedComponents = new TObjectIntHashMap<Variable>(); 
61         
62         public Visitor(ReadGraph graph, Variable rootVariable) throws DatabaseException {
63             this.rootVariable = rootVariable;
64             this.rootResource = rootVariable.getRepresents(graph);
65             this.model = Variables.getModel(graph, rootVariable);
66             this.L0 = Layer0.getInstance(graph);
67             this.STR = StructuralResource2.getInstance(graph);
68         }
69         
70         @Override
71         public void visitComponentChange(ReadGraph graph, Resource component, boolean componentItselfModified)
72                 throws DatabaseException {
73             Variable[] variables = visitedVariables.get(component);
74             if(variables == null) {
75                 variables = visitUnseenComponent(graph, component);
76                 visitedVariables.put(component, variables);
77             }
78             if(componentItselfModified)
79                 for(Variable variable : variables)
80                     modifiedComponents.put(variable, 2);
81             else
82                 for(Variable variable : variables)
83                     modifiedComponents.putIfAbsent(variable, 1);
84         }
85         
86         private Variable[] visitUnseenComponent(ReadGraph graph, Resource component) throws DatabaseException {
87             // Is root?
88             if(component.equals(rootResource))
89                 return new Variable[] { rootVariable };
90             
91             // Check if this a component type root
92             Resource componentType = graph.getPossibleObject(component, STR.Defines);
93             if(componentType != null) {
94                 ArrayList<Variable> result = new ArrayList<Variable>();
95                 Map<String,Resource> instances = graph.syncRequest(new ModelInstances(model, componentType), TransientCacheAsyncListener.<Map<String,Resource>>instance());
96                 for(Resource instance : instances.values()) {
97                     visitComponentChange(graph, instance, false);
98                     for(Variable variable : visitedVariables.get(instance))
99                         result.add(variable);
100                 }
101                 if(result.isEmpty())
102                     return EMPTY_VARIABLE_ARRAY;
103                 else
104                     return result.toArray(new Variable[result.size()]);
105             }
106             
107             // Check parent
108             Resource parent = graph.getPossibleObject(component, L0.PartOf);
109             String name = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);
110             if(parent == null || name == null || !graph.isInstanceOf(component, STR.Component))
111                 return EMPTY_VARIABLE_ARRAY;
112             
113             visitComponentChange(graph, parent, false);
114             Variable[] parentCorrespondences = visitedVariables.get(parent);
115             ArrayList<Variable> result = new ArrayList<Variable>(parentCorrespondences.length);
116             for(Variable parentCorrespondence : parentCorrespondences) {
117                 Variable correspondence = parentCorrespondence.getPossibleChild(graph, name);
118                 if(correspondence != null)
119                     result.add(correspondence);
120             }
121             if(result.isEmpty())
122                 return EMPTY_VARIABLE_ARRAY;
123             else
124                 return result.toArray(new Variable[result.size()]);
125         }
126         
127     }
128 }