package org.simantics.structural2; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.error.DatatypeConstructionException; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.util.URIStringUtils; import org.simantics.db.Issue; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.issue.StandardIssue; import org.simantics.db.common.primitiverequest.IsInstanceOf; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.PossibleIndexRoot; import org.simantics.db.common.request.PossibleObjectWithType; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.common.request.TernaryRead; import org.simantics.db.common.uri.UnescapedChildMapOfResource; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.function.All; import org.simantics.db.layer0.function.StandardChildDomainChildren; import org.simantics.db.layer0.request.PropertyInfo; import org.simantics.db.layer0.request.PropertyInfoRequest; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.AbstractChildVariable; import org.simantics.db.layer0.variable.AbstractPropertyVariable; import org.simantics.db.layer0.variable.LazyPropertyVariable; import org.simantics.db.layer0.variable.NodeSupport; import org.simantics.db.layer0.variable.StandardGraphChildVariable; import org.simantics.db.layer0.variable.StandardGraphPropertyVariable; import org.simantics.db.layer0.variable.ValueAccessor; import org.simantics.db.layer0.variable.ValueAccessorWithBinding; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.VariableMap; import org.simantics.db.layer0.variable.VariableMapImpl; import org.simantics.db.layer0.variable.VariableNode; import org.simantics.db.service.CollectionSupport; import org.simantics.issues.common.IssueUtils; import org.simantics.layer0.Layer0; import org.simantics.scl.reflection.annotations.SCLValue; import org.simantics.scl.runtime.SCLContext; import org.simantics.scl.runtime.function.Function1; import org.simantics.scl.runtime.tuple.Tuple2; import org.simantics.simulation.ontology.SimulationResource; import org.simantics.simulator.variable.NodeManager; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.structural2.procedural.Component; import org.simantics.structural2.procedural.ConnectionPoint; import org.simantics.structural2.procedural.Interface; import org.simantics.structural2.procedural.SubstructureElement; import org.simantics.structural2.procedural.Terminal; import org.simantics.structural2.queries.ConnectionComponents; import org.simantics.structural2.queries.ConnectionJoinComponents; import org.simantics.structural2.queries.ConnectionPointMapOfResource; import org.simantics.structural2.queries.PossibleConnectionPointInfo; import org.simantics.structural2.scl.CompileStructuralValueRequest; import org.simantics.structural2.scl.procedural.CompileProceduralComponentTypeRequest; import org.simantics.structural2.utils.StructuralUtils.StructuralComponentClass; import org.simantics.structural2.variables.Connection; import org.simantics.structural2.variables.StandardProceduralChildVariable; import org.simantics.utils.datastructures.MapList; import gnu.trove.map.hash.THashMap; public class Functions { @SCLValue(type="ValueAccessor") public static final ValueAccessor expressionValueAccessor = new ValueAccessorWithBinding() { public Binding getBinding() { return Bindings.STRING; } @Override public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException { if(value == null) { if(getValue(graph, context) != null) clearExpression(graph, context); return; } // Get all necessary data String expression = (String)value; Variable parent = context.getParent(graph); if(!(parent instanceof AbstractPropertyVariable)) return; AbstractPropertyVariable property = (AbstractPropertyVariable)parent; Resource propertyResource = property.getRepresents(graph); if(propertyResource == null) return; Resource container = property.getContainerResource(graph); if(container == null) return; Resource predicate = property.getPossiblePredicateResource(graph); if(predicate == null) return; Statement stat = graph.getPossibleStatement(container, predicate); StructuralResource2 STR = StructuralResource2.getInstance(graph); // Write boolean createNew = false; if(stat.isAsserted(container)) createNew = true; else if(!graph.isInstanceOf(propertyResource, STR.SCLValue)) { graph.deny(propertyResource); createNew = true; } Layer0 L0 = Layer0.getInstance(graph); if(createNew) { propertyResource = graph.newResource(); graph.claim(container, predicate, propertyResource); graph.claim(propertyResource, L0.InstanceOf, STR.SCLValue); } graph.claimLiteral(propertyResource, L0.SCLValue_expression, expression, Bindings.STRING); } private void clearExpression(WriteGraph graph, Variable context) throws DatabaseException { Variable parent = context.getParent(graph); if(!(parent instanceof AbstractPropertyVariable)) return; AbstractPropertyVariable property = (AbstractPropertyVariable)parent; Resource container = property.getContainerResource(graph); if(container == null) return; Resource predicate = property.getPossiblePredicateResource(graph); if(predicate == null) return; graph.deny(container, predicate); } @Override public Object getValue(ReadGraph graph, Variable context) throws DatabaseException { Variable parent = context.getParent(graph); if(!(parent instanceof AbstractPropertyVariable)) return null; AbstractPropertyVariable property = (AbstractPropertyVariable)parent; Resource propertyResource = property.getPossibleRepresents(graph); if(propertyResource == null) return null; StructuralResource2 STR = StructuralResource2.getInstance(graph); if(!graph.isInstanceOf(propertyResource, STR.SCLValue)) return null; Layer0 L0 = Layer0.getInstance(graph); return graph.getPossibleRelatedValue(propertyResource, L0.SCLValue_expression); } }; @SCLValue(type="ValueAccessor") public static final ValueAccessor connectionValueAccessor = new ValueAccessor() { @Override public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException { throw new UnsupportedOperationException(); } public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException { throw new UnsupportedOperationException(); } public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException { try { Object value = getValue(graph, context); Binding srcBinding = Bindings.OBJECT.getContentBinding(value); return Bindings.adapt(value, srcBinding, binding); } catch (AdaptException e) { throw new DatabaseException(e); } catch (BindingException e) { throw new DatabaseException(e); } } @Override public Object getValue(ReadGraph graph, Variable context) throws DatabaseException { StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; return new ConnectionImpl(context.getParent(graph), variable.property.predicate); } @Override public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException { try { return Datatypes.getDatatype(Connection.class); } catch (DatatypeConstructionException e) { throw new DatabaseException(e); } } }; @SCLValue(type = "VariableMap") public static VariableMap structuralChildDomainProperties = new VariableMapImpl() { public Variable getPossibleConnectionPointFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException { Map connectionPoints = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.>instance()); PropertyInfo cp = connectionPoints.get(name); if(cp == null) return null; else return new StandardGraphPropertyVariable(graph, variable, cp.predicate); } public Map collectConnectionPointsFromContext(ReadGraph graph, StructuralResource2 STR, Variable variable, Resource context, Map map, boolean needSynchronized) throws DatabaseException { if(graph.isImmutable(context)) { Map cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.>instance()); if(cps.size() == 0) return map; if(map == null) map = new THashMap(cps.size()); for(Map.Entry entry : cps.entrySet()) { String name = entry.getKey(); PropertyInfo cp = entry.getValue(); if(needSynchronized && !graph.isInstanceOf(cp.predicate, STR.SynchronizedConnectionRelation)) continue; map.put(name, new StandardGraphPropertyVariable(graph, variable, cp.predicate)); } return map; } else { Collection predicates = graph.getPredicates(context); for(Resource predicate : predicates) { PropertyInfo info = graph.isImmutable(predicate) ? graph.syncRequest(new PossibleConnectionPointInfo(predicate), TransientCacheAsyncListener.instance()) : graph.syncRequest(new PossibleConnectionPointInfo(predicate)); if(info != null) { if(map == null) map = new THashMap(4); if(needSynchronized && !graph.isInstanceOf(predicate, STR.SynchronizedConnectionRelation)) continue; map.put(info.name, new StandardGraphPropertyVariable(graph, variable, predicate)); } } return map; } } @Override public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException { final StandardGraphChildVariable variable = (StandardGraphChildVariable)context; Variable cp = getPossibleConnectionPointFromContext(graph, variable, variable.resource, name); if(cp != null) return cp; return All.getStandardChildDomainPropertyVariable(graph, context, name); } @Override public Map getVariables(ReadGraph graph, Variable context, Map map) throws DatabaseException { StandardGraphChildVariable variable = (StandardGraphChildVariable)context; StructuralResource2 STR = StructuralResource2.getInstance(graph); map = collectConnectionPointsFromContext(graph, STR, variable, variable.resource, map, false); return All.getStandardChildDomainPropertyVariables(graph, context, map); } public Map getVariables(ReadGraph graph, Variable context, String classification, Map map) throws DatabaseException { if (StructuralResource2.URIs.SynchronizedRelation.equals(classification)) { return All.getStandardChildDomainPropertyVariables(graph, context, classification, map); } else if (StructuralResource2.URIs.SynchronizedConnectionRelation.equals(classification)) { StandardGraphChildVariable variable = (StandardGraphChildVariable)context; return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, true); } else if(StructuralResource2.URIs.ConnectionRelation.equals(classification)) { StandardGraphChildVariable variable = (StandardGraphChildVariable)context; return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, false); } return super.getVariables(graph, context, classification, map); } }; static class StructuralRunContext extends ResourceRead { public StructuralRunContext(Resource resource) { super(resource); } @Override public Resource perform(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); SimulationResource SIMU = SimulationResource.getInstance(graph); Resource model = graph.sync(new PossibleIndexRoot(resource)); if(graph.isInstanceOf(model, L0.RVIContext)) { return model; } Resource configuration = graph.getPossibleObject(model, SIMU.HasConfiguration); if(configuration != null) { if(graph.isInstanceOf(configuration, L0.RVIContext)) { return configuration; } } return null; } } private static class SubstructureRequest extends VariableRead> { public SubstructureRequest(Variable context) { super(context); } @Override public List perform(ReadGraph graph) { try { Resource type = variable.getPossibleType(graph); if(type == null) return null; return CompileProceduralComponentTypeRequest.compileAndEvaluate(graph, type, variable); } catch (Throwable t) { t.printStackTrace(); return null; } } } public static List getProceduralDesc(ReadGraph graph, final Variable context) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); final Resource type = context.getPossibleType(graph); if(type != null) { if(graph.isInstanceOf(type, STR.ProceduralComponentType)) { return graph.syncRequest(new SubstructureRequest(context)); } } return null; } public static Map getProcedural(ReadGraph graph, Variable context, List elements, Map map) throws DatabaseException { if(map == null) map = new THashMap(); MapList conns = new MapList(); for(SubstructureElement sub : elements) { if(sub instanceof org.simantics.structural2.procedural.Connection) { org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)sub; for(ConnectionPoint cp : conn.connectionPoints) { if(cp instanceof Terminal) { Terminal t = (Terminal)cp; conns.add(t.component, conn); } } } } Map proceduralChildren = new THashMap(); for(SubstructureElement sub : elements) { if(sub instanceof Component) { Component comp = (Component)sub; proceduralChildren.put(comp.name, comp); } } Collection nodeChildren = All.getPossibleNodeChildren(graph, (AbstractChildVariable)context); Set used = new HashSet(nodeChildren.size()); for(Object nodeChild : nodeChildren) { @SuppressWarnings("rawtypes") NodeSupport support = ((AbstractChildVariable)context).node.support; @SuppressWarnings("rawtypes") NodeManager manager = support.manager; @SuppressWarnings("unchecked") String name = manager.getName(nodeChild); used.add(name); Component proceduralChild = proceduralChildren.get(name); if(proceduralChild != null) { map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, new VariableNode(support, nodeChild), proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name))); } } for(Map.Entry entry : proceduralChildren.entrySet()) { String name = entry.getKey(); if(used.contains(name)) continue; Component proceduralChild = entry.getValue(); map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, null, proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name))); } return map; } private static class ProceduralSubstructureRequest extends VariableRead> { public ProceduralSubstructureRequest(Variable variable) { super(variable); } @Override public Map perform(ReadGraph graph) throws DatabaseException { List elements = getProceduralDesc(graph, variable); if(elements != null) return getProcedural(graph, variable, elements, null); else return null; } } public static class StructuralTypeOverrideMap extends ResourceRead> { protected StructuralTypeOverrideMap(Resource composite) { super(composite); } @Override public Map perform(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); CollectionSupport cs = graph.getService(CollectionSupport.class); Map result = null; for(Resource override : graph.getObjects(resource, STR.HasTypeOverride)) { Resource original = graph.getSingleObject(override, STR.TypeOverride_HasOriginalType); Resource replacement = graph.getSingleObject(override, STR.TypeOverride_HasReplacementType); if(result == null) result = cs.createMap(Resource.class); result.put(original, replacement); } if(result == null) return Collections.emptyMap(); return result; } } public static class StructuralOverrideData { @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((actualRepresents == null) ? 0 : actualRepresents.hashCode()); result = prime * result + ((actualType == null) ? 0 : actualType.hashCode()); result = prime * result + ((overrideType == null) ? 0 : overrideType.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; StructuralOverrideData other = (StructuralOverrideData) obj; if (actualRepresents == null) { if (other.actualRepresents != null) return false; } else if (!actualRepresents.equals(other.actualRepresents)) return false; if (actualType == null) { if (other.actualType != null) return false; } else if (!actualType.equals(other.actualType)) return false; if (overrideType == null) { if (other.overrideType != null) return false; } else if (!overrideType.equals(other.overrideType)) return false; return true; } Resource actualRepresents; Resource actualType; Resource overrideType; public StructuralOverrideData(Resource actualRepresents, Resource actualType, Resource overrideType) { this.actualRepresents = actualRepresents; this.actualType = actualType; this.overrideType = overrideType; } public static StructuralOverrideData compute(ReadGraph graph, Variable context) throws DatabaseException { return graph.syncRequest(new StructuralOverrideDataRequest(context)); } public Resource type() { if(overrideType != null) return overrideType; return actualType; } public Resource represents() { return actualRepresents; } } private static class StructuralOverrideDataWalkRequest extends TernaryRead { public StructuralOverrideDataWalkRequest(Variable component, Resource actualRepresents, Resource actualType) { super(component, actualRepresents, actualType); } @Override public StructuralOverrideData perform(ReadGraph graph) throws DatabaseException { Variable component = parameter; Resource actualRepresents = parameter2; Resource actualType = parameter3; // System.err.println(component.getURI(graph)); Resource represents = component.getPossibleRepresents(graph); if (represents != null) { Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource container = graph .syncRequest(new PossibleObjectWithType(represents, L0.PartOf, STR.Composite)); if (container != null) { Map overrides = graph.syncRequest(new StructuralTypeOverrideMap(container), TransientCacheListener.instance()); Resource override = overrides.get(actualType); if (override != null) { return new StructuralOverrideData(actualRepresents, actualType, override); } } } Variable parent = component.getParent(graph); if (parent == null) return new StructuralOverrideData(actualRepresents, actualType, null); else return graph.syncRequest(new StructuralOverrideDataWalkRequest(parent, represents, actualType), TransientCacheListener.instance()); } } public static class StructuralOverrideDataRequest extends VariableRead { public StructuralOverrideDataRequest(Variable component) { super(component); } @Override public StructuralOverrideData perform(ReadGraph graph) throws DatabaseException { Resource represents = variable.getPossibleRepresents(graph); if(represents == null) { String uri = variable.getPossiblePropertyValue(graph, "typeURI"); if(uri != null) { Resource actualType = graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.instance()); if (graph.syncRequest(new IsInstanceOf(actualType, StructuralResource2.getInstance(graph).ReplaceableDefinedComponentType), TransientCacheListener.instance()) ) { return graph.syncRequest(new StructuralOverrideDataWalkRequest(variable, null, actualType), TransientCacheListener.instance()); } else { // can not have replaceable type return null; } } throw new DatabaseException("No type for " + variable.getURI(graph)); } else { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource possibleType = graph.getPossibleType(represents, STR.Component); if (possibleType == null) { possibleType = graph.getPossibleType(represents, Layer0.getInstance(graph).Entity); if (possibleType == null) return null; } if (graph.syncRequest(new IsInstanceOf(possibleType, STR.ReplaceableDefinedComponentType), TransientCacheListener.instance()) ) { return graph.syncRequest(new StructuralOverrideDataWalkRequest(variable, represents, possibleType), TransientCacheListener.instance()); } else { return null; } } } } private static class StructureTypeAndChildMapRequest extends ResourceRead { protected StructureTypeAndChildMapRequest(Resource resource) { super(resource); } @Override public Tuple2 perform(ReadGraph graph) throws DatabaseException { StructuralComponentClass clazz = StructuralComponentClass.get(graph, resource); if (StructuralComponentClass.DEFINED.equals(clazz)) { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource def = graph.getSingleObject(resource, STR.IsDefinedBy); Map children = graph.syncRequest(new UnescapedChildMapOfResource(def), TransientCacheListener.instance()); return new Tuple2(clazz, children); } return new Tuple2(clazz, null); } } @SCLValue(type = "VariableMap") public static VariableMap structuralChildDomainChildren = new VariableMapImpl() { @Override public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource type = context.getPossibleType(graph, STR.Component); if(type == null) return null; Tuple2 result = graph.syncRequest(new StructureTypeAndChildMapRequest(type), TransientCacheListener.instance()); StructuralComponentClass clazz = (StructuralComponentClass) result.c0; if(StructuralComponentClass.PROCEDURAL.equals(clazz)) { Map map = graph.syncRequest(new ProceduralSubstructureRequest(context), TransientCacheListener.>instance()); if(map != null) return map.get(name); return null; } else if (StructuralComponentClass.DEFINED.equals(clazz)) { Map children = (Map) result.c1; Resource child = children.get(name); if(child == null) return null; return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name); } else { Resource represents = context.getPossibleRepresents(graph); if(represents == null) return null; Map children = graph.syncRequest(new UnescapedChildMapOfResource(represents), TransientCacheListener.instance()); Resource child = children.get(name); return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name); } } @Override public Map getVariables(ReadGraph graph, Variable context, Map map) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource type = context.getPossibleType(graph, STR.Component); if(type == null) return null; StructuralComponentClass clazz = StructuralComponentClass.get(graph, type); if(StructuralComponentClass.PROCEDURAL.equals(clazz)) { Map mapPrime = graph.syncRequest(new ProceduralSubstructureRequest(context), TransientCacheListener.>instance()); if(mapPrime != null) { if(map != null) { map.putAll(mapPrime); return map; } else return mapPrime; } return map; } else if (StructuralComponentClass.DEFINED.equals(clazz)) { Resource def = graph.getSingleObject(type, STR.IsDefinedBy); Map children = graph.syncRequest(new UnescapedChildMapOfResource(def), TransientCacheListener.instance()); return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map); } else { Resource represents = context.getPossibleRepresents(graph); if(represents == null) return null; Map children = graph.syncRequest(new UnescapedChildMapOfResource(represents)); return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map); } } }; @SCLValue(type = "VariableMap") public static VariableMap structuralRunDomainChildren = new VariableMapImpl() { @Override public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException { Resource ctx = graph.syncRequest(new StructuralRunContext(context.getRepresents(graph))); if(ctx == null) return null; Map children = graph.syncRequest(new UnescapedChildMapOfResource(ctx)); Resource child = children.get(name); return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name); } @Override public Map getVariables(ReadGraph graph, Variable context, Map map) throws DatabaseException { Resource ctx = graph.syncRequest(new StructuralRunContext(context.getRepresents(graph))); if(ctx == null) return map; Map children = graph.syncRequest(new UnescapedChildMapOfResource(ctx)); return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map); } }; @SCLValue(type = "ReadGraph -> [Resource] -> [Resource]") public static List connectionExtension(ReadGraph graph, List rs) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); HashSet extension = new HashSet(8); for(Resource r : rs) { if(graph.isInstanceOf(r, STR.Connection)) { extension.addAll(graph.syncRequest(new ConnectionComponents(r), TransientCacheListener.>instance())); } if(graph.isInstanceOf(r, STR.ConnectionJoin)) { extension.addAll(graph.syncRequest(new ConnectionJoinComponents(r), TransientCacheListener.>instance())); } } HashSet components = new HashSet(8); for(Resource r : extension) { components.addAll(graph.sync(new ObjectsWithType(r, STR.Connects, STR.Component))); } if(!extension.isEmpty()) { ArrayList result = new ArrayList(rs.size() + extension.size()); result.addAll(rs); result.addAll(extension); result.addAll(components); rs = result; } return rs; } @SCLValue(type = "ReadGraph -> Resource -> [Issue]") public static List connectionValidator(ReadGraph graph, Resource component) throws DatabaseException { if(!graph.hasStatement(component)) return Collections.emptyList(); ArrayList result = new ArrayList(); Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 sr = StructuralResource2.getInstance(graph); Resource type = graph.getSingleType(component, sr.Component); Set requiredConnections = new HashSet(); for(Resource connectionRelation : graph.sync(new ObjectsWithType(type, L0.ConsistsOf, sr.ConnectionRelation))) { Boolean required = graph.getPossibleRelatedValue(connectionRelation, sr.ConnectionRelation_connectionRequired, Bindings.BOOLEAN); if(required != null && required) requiredConnections.add(connectionRelation); } Set connections = new HashSet(); for(Statement stm : graph.getStatements(component, sr.IsConnectedTo)) { connections.add(stm.getPredicate()); connections.addAll(graph.getSuperrelations(stm.getPredicate())); } for(Resource req : requiredConnections) { if(!connections.contains(req)) { result.add(new StandardIssue(sr.ConnectionValidationConstraint_ErrorIssue, component, req)); } } return result; } @SCLValue(type = "ReadGraph -> Resource -> Variable -> String") public static String connectionIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException { List contexts = IssueUtils.getContextsForProperty(graph, property); String attributeName = graph.getRelatedValue(contexts.get(1), Layer0.getInstance(graph).HasName); return "'" + attributeName + "' should be connected."; } public static class InterfacePathMap extends VariableRead>> { public InterfacePathMap(Variable context) { super(context); } @Override public GraphMap> perform(ReadGraph graph) throws DatabaseException { return new GraphMap>() { @Override Map get(ReadGraph graph, String key) throws DatabaseException { Variable child = variable.getChild(graph, key); Map childMap = new THashMap(); Collection paths = computeInterfacePaths(graph, child);//child.getPossiblePropertyValue(graph, "proceduralConnectionPointPath"); if(paths != null) { for(InterfaceResolution r : paths) { childMap.put(r.interfaceName, r); } } return childMap; } }; } } public static String resolveInterfacePath(ReadGraph graph, Variable context, String component, Resource relation) throws DatabaseException { GraphMap> map = graph.syncRequest(new InterfacePathMap(context), TransientCacheListener.>>instance()); Map childMap = map.get(graph, component); if(childMap == null) return ""; PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheListener.instance()); InterfaceResolution match = childMap.get(info.name); if(match != null) { String comp = URIStringUtils.escape(component); Variable newContext = context.getChild(graph, component); return "/" + comp + resolveInterfacePath(graph, newContext, match.componentName, match.connectionPoint); } else { return "/" + URIStringUtils.escape(component) + "#" + URIStringUtils.escape(info.name); } } public static class InterfaceResolution { public Resource interfaceConnectionPoint; public String interfaceName; public String componentName; public Resource connectionPoint; public InterfaceResolution(Resource interfaceConnectionPoint, String interfaceName, String componentName, Resource connectionPoint) { this.interfaceConnectionPoint = interfaceConnectionPoint; this.interfaceName = interfaceName; this.componentName = componentName; this.connectionPoint = connectionPoint; } } public static Collection computeInterfacePaths(ReadGraph graph, Variable variable) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource type = variable.getPossibleType(graph); if(type != null) { if(graph.isInstanceOf(type, STR.ProceduralComponentType)) { ArrayList result = new ArrayList(); List elements = getProceduralDesc(graph, variable); if(elements != null) { for(SubstructureElement e : elements) { if(e instanceof org.simantics.structural2.procedural.Connection) { org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)e; Interface inf = null; for(ConnectionPoint cp : conn.connectionPoints) { if(cp instanceof Interface) { if(inf != null) throw new DatabaseException("Multiple interfaces referenced in procedural connection."); inf = (Interface)cp; } } if(inf != null && conn.connectionPoints.size() > 1) { Layer0 L0 = Layer0.getInstance(graph); String cpName = URIStringUtils.escape( graph.getRelatedValue(inf.relation, L0.HasName, Bindings.STRING) ); for(ConnectionPoint cp : conn.connectionPoints) { if(cp == inf) continue; Terminal t = (Terminal)cp; result.add(new InterfaceResolution(inf.relation, cpName, t.component, t.relation)); } } } } } return result; } final Collection interfaces = graph.syncRequest(new DefinedUCInterfaceMap(type), TransientCacheListener.instance()); if(interfaces != null) return interfaces; } return BUILTIN_STRUCTURAL_CPS; } static class InterfacePathRequest extends VariableRead> { public InterfacePathRequest(Variable variable) { super(variable); } @Override public Collection perform(ReadGraph graph) throws DatabaseException { return computeInterfacePaths(graph, variable); } } public static final Collection BUILTIN_STRUCTURAL_CPS = new ArrayList(); @SCLValue(type = "ReadGraph -> Resource -> Variable -> a") public static Object computeExpression(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { return CompileStructuralValueRequest.compileAndEvaluate(graph, context); } public static Object computeExpressionInContext(ReadGraph graph, Variable context, final String expression) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.get("graph"); try { Function1 exp = graph.syncRequest(new CompileStructuralValueRequest(graph, context) { protected String getExpressionText(ReadGraph graph) throws DatabaseException { return expression; } }, TransientCacheListener.instance()); sclContext.put("graph", graph); return exp.apply(context); } catch (DatabaseException e) { throw (DatabaseException)e; } catch (Throwable t) { throw new DatabaseException(t); } finally { sclContext.put("graph", oldGraph); } } static abstract class InterfacePathProperty extends LazyPropertyVariable { public InterfacePathProperty(Variable parent) { super(parent, "proceduralConnectionPointPath", Bindings.STRING_ARRAY); } @Override public T getValue(ReadGraph graph, Binding binding) throws DatabaseException { return getValue(graph); } } static abstract class GraphMap { abstract Value get(ReadGraph graph, String key) throws DatabaseException; } }