package org.simantics.structural2.utils; import gnu.trove.set.hash.THashSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.datatypes.literal.GUID; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.CommentMetadata; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.PossibleTypedParent; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.exception.MissingVariableException; import org.simantics.db.layer0.request.InstantiateRequest; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.variable.Variable; import org.simantics.layer0.Layer0; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.structural2.internal.queries.ConnectedTo; import org.simantics.structural2.internal.queries.RelatedConnections; import org.simantics.structural2.internal.queries.RelatedConnectionsOfConnectionJoin; import org.simantics.structural2.queries.Terminal; import org.simantics.structural2.variables.Connection; import org.simantics.utils.datastructures.Pair; /** * A utility class for manipulating structural models. * * @author Hannu Niemistö */ public class StructuralUtils { public static Collection getConnectionRelations(ReadGraph graph, Resource componentType) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); return graph.syncRequest(new ObjectsWithType(componentType, L0.DomainOf, STR.ConnectionRelation)); } public static Collection getPropertyRelations(ReadGraph graph, Resource componentType) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); ArrayList result = new ArrayList(); for(Resource relation : graph.getObjects(componentType, L0.DomainOf)) if(graph.isSubrelationOf(relation, L0.HasProperty)) result.add(relation); return result; } public static boolean isDomainOfRelation(ReadGraph graph, Resource componentType, Resource connectionRelation) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); for(Resource domain : graph.getObjects(connectionRelation, L0.HasDomain)) if(graph.isInheritedFrom(componentType, domain)) return true; return false; } public static void addConnectionPoint(WriteGraph g, Resource componentType, Resource connectionPoint) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); g.claim(connectionPoint, L0.HasDomain, componentType); } public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy) throws DatabaseException { String proposition = NameUtils.getSafeName(g, copy); String newName = NameUtils.findFreshName(g, proposition, componentType); return createConnectionPoint(g, componentType, copy, newName); } public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException { return createConnectionPointP(g, componentType, copy, name).first; } public static Pair createConnectionPointP(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); // Create the connection point Resource connectionPoint = g.newResource(); Resource connectionPointInv = g.newResource(); for (Resource superrelation : g.getObjects(copy, L0.SubrelationOf)) { g.claim(connectionPoint, L0.SubrelationOf, null, superrelation); Resource inverse = g.getPossibleInverse(superrelation); if (inverse != null) g.claim(connectionPointInv, L0.SubrelationOf, null, inverse); } for (Resource type : g.getObjects(copy, L0.InstanceOf)) { g.claim(connectionPoint, L0.InstanceOf, null, type); } for (Resource attachment : g.getObjects(copy, STR.HasAttachmentRelation)) { g.claim(connectionPoint, STR.HasAttachmentRelation, attachment); } for (Statement stm : g.getStatements(copy, STR.AllowsConnectionType)) { if (!stm.isAsserted(copy)) { g.claim(connectionPoint, stm.getPredicate(), stm.getObject()); } } g.claim(connectionPoint, L0.InverseOf, connectionPointInv); g.claimLiteral(connectionPoint, L0.HasName, name, Bindings.STRING); g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv); g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING); StructuralUtils.addConnectionPoint(g, componentType, connectionPoint); g.claim(componentType, L0.ConsistsOf, connectionPoint); return Pair.make(connectionPoint, connectionPointInv); } /** * Creates a new component and the templates associated with it. * This method does not check whether there already exists * a component with the same name and parent. * @param g * @param parent The parent composite of the new component. * @param name The name of the new component. * @param componentType The type of the new component. * @return * @throws DatabaseException */ public static Resource newComponent(WriteGraph g, Resource parent, String name, Resource componentType) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); HashMap parameters = new HashMap(); parameters.put("parent", parent); InstantiateRequest ir = new InstantiateRequest(componentType, parameters); Resource component = ir.perform(g); g.claim(component, L0.HasName, Layer0Utils.literal(g, name)); g.claim(component, L0.HasLabel, Layer0Utils.literal(g, "")); g.addLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, GUID.random(), GUID.BINDING); g.claim(parent, L0.ConsistsOf, component); // Add comment to change set. CommentMetadata cm = g.getMetadata(CommentMetadata.class); g.addMetadata(cm.add("Created component " + component)); return component; } /** * Returns all child components of a composite. */ public static Collection getChildComponents(ReadGraph g, Resource parent) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); Collection allChildren = g.getObjects(parent, L0.ConsistsOf); ArrayList result = new ArrayList(allChildren.size()); for(Resource child : allChildren) // Composite may contain other things than components, therefore we must do checking if(g.isInstanceOf(child, STR.Component)) result.add(child); return result; } /** * Returns the component type of the given component or null if the * parameter is not a component. */ public static Resource getComponentType(ReadGraph g, Resource component) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(g); return g.getPossibleType(component, STR.Component); } /** * Returns the definitions of the component type or null, if the component * type does not have a definition. */ public static Resource getComponentTypeDefinition(ReadGraph g, Resource componentType) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(g); return g.getPossibleObject(componentType, STR.IsDefinedBy); } /** * Returns all (component,connectionRelation) pairs that are connected * to the given component and connectionRelation. * @param component * @param bindingRelation * @return */ public static Set getRelatedTerminals(RequestProcessor g, Resource component, Resource connectionRelation) throws DatabaseException { return g.syncRequest(new ConnectedTo(component, connectionRelation)); } /** * Returns all connections that are reachable from the given connection * with IsJoinedBy-relation including the given connection itself. */ public static Set getRelatedConnections(RequestProcessor g, Resource connection) throws DatabaseException { return g.syncRequest(new RelatedConnections(connection)); } /** * Returns all connections that are reachable from the given connection join. * */ public static Set getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin) throws DatabaseException { return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin)); } /** * Returns all connections that are reachable from the given connection join * without visiting the resources in the collection excludedConnections. */ public static Set getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin, Collection excludedConnections) throws DatabaseException { return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin, excludedConnections)); } /** * Returns true if the given composite is a parent of some/all components * where the connection is attached to. */ public static boolean isConnectionInComposite(ReadGraph g, Resource connection, Resource composite) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(g); Layer0 L0 = Layer0.getInstance(g); Collection connects = g.getObjects(connection, STR.Connects); if (!connects.isEmpty()) { for(Resource component : connects) for(Resource parent : g.getObjects(component, L0.PartOf)) if(parent.equals(composite)) return true; } else { Set joinedComposites = null; for(Resource join : g.getObjects(connection, STR.IsJoinedBy)) { Collection joined = g.getObjects(join, STR.JoinsComposite); if (joinedComposites == null) { joinedComposites = new THashSet(joined); } else { joinedComposites.retainAll(joined); } } if (joinedComposites != null && joinedComposites.size() == 1) { return joinedComposites.contains(composite); } } return false; } public static Variable getConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); String relationName = graph.getRelatedValue(relation, L0.HasName, Bindings.STRING); return component.getProperty(graph, relationName); } public static Variable getPossibleConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException { try { return getConnectionPoint(graph, component, relation); } catch (MissingVariableException e) { return null; } } public static Variable getPossibleConnectionTo(ReadGraph graph, Variable component, Resource relation) throws DatabaseException { Variable property = component.getPossibleProperty(graph, relation); if(property == null) return null; Connection conn = property.getPossibleValue(graph); if(conn == null) return null; Collection cps = conn.getConnectionPoints(graph, null); if(cps.size() == 2) { for(Variable var : cps) { if(property.equals(var)) continue; return var; } } return null; } public static boolean isImmutable(ReadGraph graph, Resource r) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource uc = graph.syncRequest(new PossibleTypedParent(r, STR.ComponentType)); return graph.isImmutable(r) // Anything under a published or locked user component is published as well || (uc != null && (Layer0Utils.isPublished(graph, uc) || graph.hasStatement(uc, STR.ComponentType_Locked))) // Anything under a published container (shared library) is published as well || Layer0Utils.isContainerPublished(graph, r) ; } }