package org.simantics.structural2.variables; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.NoSingleResultException; import org.simantics.db.layer0.function.All; import org.simantics.db.layer0.request.ClassificationsRequest; import org.simantics.db.layer0.variable.AbstractChildVariable; import org.simantics.db.layer0.variable.NodeSupport; import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable; import org.simantics.db.layer0.variable.StandardConstantGraphPropertyVariable; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.VariableNode; import org.simantics.layer0.Layer0; import org.simantics.simulator.variable.NodeManager; import org.simantics.structural2.Functions; import org.simantics.structural2.procedural.Connection; import org.simantics.structural2.procedural.ConnectionPoint; import org.simantics.structural2.procedural.Expression; import org.simantics.structural2.procedural.Interface; import org.simantics.structural2.procedural.Property; import org.simantics.structural2.procedural.Terminal; import org.simantics.utils.datastructures.Pair; import org.slf4j.LoggerFactory; public class StandardProceduralChildVariable extends AbstractChildVariable { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(StandardProceduralChildVariable.class); /* * Extension points * */ public Variable getPossibleSpecialChild(ReadGraph graph, String name) throws DatabaseException { return null; } public void collectSpecialChildren(ReadGraph graph, Map children) throws DatabaseException { } /* * Standard implementation * */ final protected String name; final protected Variable parent; final private Resource type; final private Map properties; final private List propertyIdentity; public static class FixedConnection implements org.simantics.structural2.variables.Connection { final public Collection> cps = new ArrayList>(); final private Variable parent; public FixedConnection(Variable parent) { this.parent = parent; } @Override public Collection getConnectionPoints(ReadGraph graph, Resource relationType) throws DatabaseException { Set result = new THashSet(); for(Pair cp : cps) { Variable component = cp.first == null ? parent : parent.getChild(graph, cp.first); Variable cp2 = component.getPossibleProperty(graph, cp.second); if(cp2 != null) for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, component, cp.second, relationType)) { result.add(desc.getVariable(graph)); } else LOGGER.warn("no cp " + cp.first + " for " + component.getURI(graph)); } return result; } @Override public Collection getConnectionPointURIs(ReadGraph graph, Resource relationType) throws DatabaseException { Set result = new THashSet(); for(Pair cp : cps) { Variable component = cp.first == null ? parent : parent.getChild(graph, cp.first); Variable cp2 = component.getPossibleProperty(graph, cp.second); if(cp2 != null) for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, component, cp.second, relationType)) { result.add(desc.getURI(graph)); } else LOGGER.warn("no cp " + cp.first + " for " + component.getURI(graph)); } return result; } @Override public Collection getConnectionPointDescriptors(ReadGraph graph, Resource relationType) throws DatabaseException { Set result = new THashSet(); for(Pair cp : cps) { Variable component = cp.first == null ? parent : parent.getChild(graph, cp.first); Variable cp2 = component.getPossibleProperty(graph, cp.second); if(cp2 != null) result.addAll(ConnectionBrowser.flatten(graph, component, cp.second, relationType)); else LOGGER.warn("no cp " + cp.first + " for " + component.getURI(graph)); } return result; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((cps == null) ? 0 : cps.hashCode()); result = prime * result + ((parent == null) ? 0 : parent.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; FixedConnection other = (FixedConnection) obj; if (cps == null) { if (other.cps != null) return false; } else if (!cps.equals(other.cps)) return false; if (parent == null) { if (other.parent != null) return false; } else if (!parent.equals(other.parent)) return false; return true; } } public StandardProceduralChildVariable(ReadGraph graph, Variable parent, VariableNode node, String name, Resource type, List properties, Collection conns) throws DatabaseException { super(node); assert name != null; assert type != null; this.name = name; this.parent = parent; this.type = type; this.properties = new THashMap(); this.propertyIdentity = new ArrayList(properties.size()+conns.size()); propertyIdentity.addAll(properties); propertyIdentity.addAll(conns); Layer0 L0 = Layer0.getInstance(graph); Map assertedProperties = new THashMap(); for(Statement stm : graph.getAssertedStatements(type, L0.HasProperty)) { String pn = graph.getRelatedValue(stm.getPredicate(), L0.HasName, Bindings.STRING); assertedProperties.put(pn, stm); } Collection nodeProperties = All.getPossibleNodeProperties(graph, (AbstractChildVariable)this); Set used = new HashSet(nodeProperties.size()); for(Object nodeProperty : nodeProperties) { @SuppressWarnings("rawtypes") NodeSupport support = node.support; @SuppressWarnings("rawtypes") NodeManager manager = support.manager; @SuppressWarnings("unchecked") String pName = manager.getName(nodeProperty); used.add(pName); Statement assertedProperty = assertedProperties.get(pName); if(assertedProperty != null) { this.properties.put(pName, new StandardAssertedGraphPropertyVariable(graph, this, new VariableNode(support, nodeProperty), assertedProperty.getSubject(), assertedProperty.getPredicate(), assertedProperty.getObject())); } } for(Map.Entry entry : assertedProperties.entrySet()) { String pName = entry.getKey(); if(used.contains(pName)) continue; Statement assertedProperty = entry.getValue(); this.properties.put(pName, new StandardAssertedGraphPropertyVariable(graph, this, null, assertedProperty.getSubject(), assertedProperty.getPredicate(), assertedProperty.getObject())); } for(Property p : properties) { String pn = graph.getRelatedValue(p.relation, L0.HasName, Bindings.STRING); if(p.value == null) { Logger.defaultLogError("StandardProceduralChildVariable " + getURI(graph) + ": null value for property " + pn); } else if (p.value instanceof Expression) { Expression expression = (Expression)p.value; this.properties.put(pn, new StructuralProceduralExpressionPropertyVariable(graph, this, p.relation, expression.text) ); } else { this.properties.put(pn, new StandardConstantGraphPropertyVariable(graph, this, p.relation, p.value) ); } } Map map = new HashMap(); for(Connection conn : conns) { Resource p = null; List> cps = new ArrayList>(); for(ConnectionPoint cp : conn.connectionPoints) { if(cp instanceof Terminal) { Terminal t = (Terminal)cp; if(t.component.equals(name)) { p = t.relation; continue; } cps.add(Pair.make(t.component, t.relation)); } if(cp instanceof Interface) { Interface inf = (Interface)cp; cps.add(new Pair(null, inf.relation)); } } if(p != null) { FixedConnection fc = map.get(p); if(fc == null) { fc = new FixedConnection(parent); map.put(p, fc); } fc.cps.addAll(cps); } } for(Map.Entry entry : map.entrySet()) { Resource cp = entry.getKey(); String cpName = graph.getRelatedValue(cp, L0.HasName, Bindings.STRING); this.properties.put(cpName, new StandardConstantGraphPropertyVariable(graph, this, cp, entry.getValue())); } } @Override public void validate(ReadGraph graph) throws DatabaseException { } @Override public Resource getType(ReadGraph graph) throws DatabaseException { return type; } @Override public Resource getPossibleType(ReadGraph graph) throws DatabaseException { return type; } @Override public Resource getType(ReadGraph graph, Resource baseType) throws DatabaseException { if (graph.isInheritedFrom(type, baseType)) return type; throw new NoSingleResultException("variable " + getPossibleURI(graph) + " has no type", -1); } @Override public Resource getPossibleType(ReadGraph graph, Resource baseType) throws DatabaseException { return graph.isInheritedFrom(type, baseType) ? type : null; } @Override protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException { return properties.get(name); } @Override public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException { return Functions.structuralChildDomainChildren.getVariable(graph, this, name); } @Override public Map collectDomainProperties(ReadGraph graph, Map properties) throws DatabaseException { if(!this.properties.isEmpty()) { if(properties == null) properties = new THashMap(this.properties.size()); properties.putAll(this.properties); } return properties; } @Override public Collection getChildren(ReadGraph graph) throws DatabaseException { Map result = Functions.structuralChildDomainChildren.getVariables(graph, this, null); if(result == null) return Collections.emptyList(); else return result.values(); } public Set getClassifications(ReadGraph graph) throws DatabaseException { Resource type = getPossibleType(graph); return (type != null) ? graph.syncRequest(new ClassificationsRequest(Collections.singleton(type))) : Collections.emptySet(); } @Override public String getName(ReadGraph graph) throws DatabaseException { return name; } @Override public Variable getParent(ReadGraph graph) throws DatabaseException { return parent; } @Override final public Resource getRepresents(ReadGraph graph) throws DatabaseException { return null; } @Override public int hashCode() { return parent.hashCode() + 31*name.hashCode() + 41*type.hashCode() + 71*System.identityHashCode(propertyIdentity); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; StandardProceduralChildVariable other = (StandardProceduralChildVariable) obj; if(!name.equals(other.name)) return false; if(!type.equals(other.type)) return false; if(!parent.equals(other.parent)) return false; if(propertyIdentity != other.propertyIdentity) return false; return true; } }