package org.simantics.structural2.utils; import gnu.trove.set.hash.THashSet; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.changeset.ChangeVisitor; import org.simantics.db.layer0.changeset.MetadataUtils; import org.simantics.db.layer0.genericrelation.DependencyChanges; import org.simantics.db.layer0.genericrelation.DependencyChanges.Change; import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentAddition; import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentModification; import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentRemoval; import org.simantics.db.layer0.request.ModelInstances; import org.simantics.layer0.Layer0; import org.simantics.structural.stubs.StructuralResource2; public class StructuralMetadataUtils { private static ChangeVisitor getChangeVisitor(final ReadGraph graph, final Resource model, final StructuralChangeVisitor visitor) throws DatabaseException { return new ChangeVisitor() { Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); THashSet visited = new THashSet(); Resource IsLiftedAs = graph.getResource("http://www.simantics.org/Diagram-2.2/IsLiftedAs"); @Override public void visit(ReadGraph graph, Change change, boolean inverted) throws DatabaseException { switch(change.getType()) { case COMPONENT_ADDITION: { ComponentAddition addition = (ComponentAddition)change; if(inverted) visitor.visitComponentChange(graph, addition.parent, false); else visitor.visitComponentChange(graph, addition.component, true); } break; case COMPONENT_MODIFICATION: { ComponentModification modification = (ComponentModification)change; handleModification(graph, modification.component); } break; case COMPONENT_REMOVAL: { ComponentRemoval removal = (ComponentRemoval)change; if(inverted) visitor.visitComponentChange(graph, removal.component, true); else visitor.visitComponentChange(graph, removal.parent, false); } break; case LINK_CHANGE: // Link changes should not affect the structural configuration break; } } void handleModification(ReadGraph graph, Resource resource) throws DatabaseException { if(!visited.add(resource)) return; if(!graph.hasStatement(resource)) return; //System.out.println("handleModification: " + graph.getPossibleURI(resource)); if(graph.isInstanceOf(resource, STR.Component)) visitor.visitComponentChange(graph, resource, true); else if(graph.isInstanceOf(resource, STR.Connection)) for(Resource connection : StructuralUtils.getRelatedConnections(graph, resource)) handleConnectionChange(graph, connection); else if(graph.isInstanceOf(resource, STR.ConnectionJoin)) for(Resource connection : StructuralUtils.getRelatedConnectionsOfConnectionJoin(graph, resource)) handleConnectionChange(graph, connection); else if(graph.isInstanceOf(resource, STR.ComponentType)) for(Resource instance : graph.syncRequest(new ModelInstances(model, resource)).values()) visitor.visitComponentChange(graph, instance, true); else { Resource connectionRelation = graph.getPossibleObject(resource, IsLiftedAs); if(connectionRelation != null) handleConnectionRelation(graph, connectionRelation); else for(Resource parent : graph.getObjects(resource, L0.IsDependencyOf)) handleModification(graph, parent); } } void handleConnectionChange(ReadGraph graph, Resource connection) throws DatabaseException { for(Resource component : graph.getObjects(connection, STR.Connects)) visitor.visitComponentChange(graph, component, true); for(Resource connectionRelation : graph.getObjects(connection, STR.Binds)) handleConnectionRelation(graph, connectionRelation); } void handleConnectionRelation(ReadGraph graph, Resource connectionRelation) throws DatabaseException { Resource componentType = graph.getPossibleObject(connectionRelation, L0.HasDomain); if(componentType == null) return; for(Resource instance : graph.syncRequest(new ModelInstances(model, componentType)).values()) for(Resource connection2 : graph.getObjects(instance, connectionRelation)) handleConnectionChange(graph, connection2); } }; } /** * Finds all structural changes made to the given {@code model} from the given revision and calls * the {@code visitor} for them. * The function processes raw metadata about modifications to resources and produces changes * to components. It implements the following rules: * */ public static void visitStructuralChangesFrom(final ReadGraph graph, final Resource model, long fromRevision, final StructuralChangeVisitor visitor) throws DatabaseException { MetadataUtils.visitDependencyChangesFrom(graph, model, fromRevision, getChangeVisitor(graph, model, visitor)); } public static void visitStructuralChangesFrom(final ReadGraph graph, final Resource model, DependencyChanges.Change[] changes, final StructuralChangeVisitor visitor) throws DatabaseException { MetadataUtils.visitDependencyChangesFrom2(graph, model, changes, getChangeVisitor(graph, model, visitor)); } }