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 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 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 visitedVariables = new THashMap(); Layer0 L0; StructuralResource2 STR; TObjectIntHashMap modifiedComponents = new TObjectIntHashMap(); 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 result = new ArrayList(); Map instances = graph.syncRequest(new ModelInstances(model, componentType), TransientCacheAsyncListener.>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 result = new ArrayList(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()]); } } }