package org.simantics.structural2.variables; import java.util.Collection; import org.simantics.databoard.Bindings; import org.simantics.databoard.util.URIStringUtils; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.structural2.DefinedUCInterfaceMap; import org.simantics.structural2.Functions; import org.simantics.structural2.Functions.InterfaceResolution; import org.simantics.structural2.utils.StructuralUtils.StructuralComponentClass; import org.simantics.structural2.variables.ConnectionBrowser.IsLeafType; /* * This connection descriptor * * -has not been lifted into interface * -has a structural configuration defined as resources * -might not be drilled * * Note: these are constructed after climb (before drill) phase of the connection browser. This means that * the component can still contain sub structure during connection browsing. This means that some descriptors * are not final and are replaced by correct descriptors during drill phase. * */ class ActualConnectionDescriptor extends AbstractVariableConnectionPointDescriptor { /* * This is the nearest known ancestor variable */ final Variable root; /* * A component on variable path under the root variable. */ final Resource component; /* * TODO */ final Resource componentType; /* * The connection point that has type of the component as its domain */ final Resource cp; public ActualConnectionDescriptor(Variable root, Resource component, Resource componentType, Resource cp) { this.root = root; this.component = component; this.componentType = componentType; this.cp = cp; } static class ActualConnectionDescriptorInterfaceDescription extends UnaryRead> { public ActualConnectionDescriptorInterfaceDescription(ActualConnectionDescriptor desc) { super(desc); } @Override public Collection perform(ReadGraph graph) throws DatabaseException { // ConnectionBrowser.reportDescriptor(graph, parameter); /* * The componentType is the possibly replaced (STR.ReplaceableDefinedComponentType) type */ StructuralComponentClass clazz = StructuralComponentClass.get(graph, parameter.componentType); if(StructuralComponentClass.PRIMITIVE.equals(clazz)) { return null; } else if(StructuralComponentClass.DEFINED.equals(clazz)) { final Collection interfaces = graph.syncRequest(new DefinedUCInterfaceMap(parameter.componentType)); if(interfaces != null) return interfaces; else return Functions.BUILTIN_STRUCTURAL_CPS; } else if(StructuralComponentClass.REPLACEABLE.equals(clazz)) { throw new DatabaseException("ConnectionBrowser does not support nested replaceable defined structural types."); } else { return Functions.computeInterfacePaths(graph, parameter.getVariable(graph).getParent(graph)); } } } @Override public boolean isLeaf(ReadGraph graph) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource type = graph.getPossibleType(component, STR.Component); return type != null ? graph.syncRequest(new IsLeafType(type)) : false; } @Override public Collection getInterfaceDescription(ReadGraph graph) throws DatabaseException { return graph.syncRequest(new ActualConnectionDescriptorInterfaceDescription(this), TransientCacheAsyncListener.>instance()); } public Resource getConnectionPointResource(ReadGraph graph) throws DatabaseException { return cp; } static class ComputeVariable extends UnaryRead { public ComputeVariable(ActualConnectionDescriptor desc) { super(desc); } @Override public Variable perform(ReadGraph graph) throws DatabaseException { Variable c = ConnectionBrowser.resolve(graph, parameter.root, parameter.component); if(c != null) { Variable cnp = c.getPossibleProperty(graph, parameter.cp); if(cnp != null) { return cnp; } } throw new DatabaseException("Unresolved connection point (root=" + parameter.root.getURI(graph) + ", component=" + NameUtils.getURIOrSafeNameInternal(graph, parameter.component) + ", cp=" + NameUtils.getURIOrSafeNameInternal(graph, parameter.cp) + ")"); } } @Override public Variable getVariable(ReadGraph graph) throws DatabaseException { return graph.syncRequest(new ComputeVariable(this), TransientCacheAsyncListener.instance()); } @Override public String getURI(ReadGraph graph) throws DatabaseException { Variable var = getVariable(graph); return var.getURI(graph); } @Override public boolean isFlattenedFrom(ReadGraph graph, Variable possiblyStructuralCp) throws DatabaseException { // This is a top-level configured connection point - we return true if possiblyStructuralCp is actually this connection point Resource otherCp = possiblyStructuralCp.getPossiblePredicateResource(graph); if(!cp.equals(otherCp)) return false; Variable otherComponentVariable = possiblyStructuralCp.getParent(graph); Resource otherComponent = otherComponentVariable.getPossibleRepresents(graph); if(!component.equals(otherComponent)) return false; Variable otherContainer = otherComponentVariable.getParent(graph); if(otherContainer.equals(root)) return true; return getVariable(graph).equals(possiblyStructuralCp); } @Override public String getRelativeRVI(ReadGraph graph, Variable base) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); String cpName = graph.getRelatedValue(cp, L0.HasName, Bindings.STRING); if(cpName.startsWith("/")) { ModelingResources MOD = ModelingResources.getInstance(graph); if(graph.isInstanceOf(component, MOD.ReferenceElement)) { return "#" + cpName; } } if(root.equals(base.getParent(graph))) { StringBuilder b = new StringBuilder(); b.append("./"); String cName = graph.getRelatedValue(component, L0.HasName, Bindings.STRING); b.append(URIStringUtils.escape(cName)); b.append("#"); b.append(cpName); return b.toString(); } return super.getRelativeRVI(graph, base); } }