1 package org.simantics.structural2.utils;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
9 import org.simantics.databoard.Bindings;
10 import org.simantics.db.ReadGraph;
11 import org.simantics.db.RequestProcessor;
12 import org.simantics.db.Resource;
13 import org.simantics.db.Statement;
14 import org.simantics.db.WriteGraph;
15 import org.simantics.db.common.CommentMetadata;
16 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
17 import org.simantics.db.common.request.ObjectsWithType;
18 import org.simantics.db.common.request.PossibleTypedParent;
19 import org.simantics.db.common.utils.NameUtils;
20 import org.simantics.db.exception.DatabaseException;
21 import org.simantics.db.layer0.exception.MissingVariableException;
22 import org.simantics.db.layer0.request.InstantiateRequest;
23 import org.simantics.db.layer0.util.Layer0Utils;
24 import org.simantics.db.layer0.variable.Variable;
25 import org.simantics.layer0.Layer0;
26 import org.simantics.structural.stubs.StructuralResource2;
27 import org.simantics.structural2.Functions.StructuralOverrideData;
28 import org.simantics.structural2.internal.queries.ConnectedTo;
29 import org.simantics.structural2.internal.queries.RelatedConnections;
30 import org.simantics.structural2.internal.queries.RelatedConnectionsOfConnectionJoin;
31 import org.simantics.structural2.queries.Terminal;
32 import org.simantics.structural2.variables.Connection;
33 import org.simantics.utils.datastructures.Pair;
35 import gnu.trove.set.hash.THashSet;
38 * A utility class for manipulating structural models.
40 * @author Hannu Niemistö
42 public class StructuralUtils {
44 public static enum StructuralComponentClass {
46 PRIMITIVE,REPLACEABLE,DEFINED,PROCEDURAL;
48 public static StructuralComponentClass get(ReadGraph graph, Resource componentType) throws DatabaseException {
49 StructuralResource2 STR = StructuralResource2.getInstance(graph);
50 if(graph.isInstanceOf(componentType, STR.ProceduralComponentType))
51 return StructuralComponentClass.PROCEDURAL;
52 else if(graph.hasStatement(componentType, STR.IsDefinedBy))
53 return StructuralComponentClass.DEFINED;
54 else if(graph.isInstanceOf(componentType, STR.ReplaceableDefinedComponentType))
55 return StructuralComponentClass.REPLACEABLE;
57 return StructuralComponentClass.PRIMITIVE;
62 public static Collection<Resource> getConnectionRelations(ReadGraph graph, Resource componentType) throws DatabaseException {
63 Layer0 L0 = Layer0.getInstance(graph);
64 StructuralResource2 STR = StructuralResource2.getInstance(graph);
65 return graph.syncRequest(new ObjectsWithType(componentType, L0.DomainOf, STR.ConnectionRelation));
68 public static Collection<Resource> getPropertyRelations(ReadGraph graph, Resource componentType) throws DatabaseException {
69 Layer0 L0 = Layer0.getInstance(graph);
70 ArrayList<Resource> result = new ArrayList<Resource>();
71 for(Resource relation : graph.getObjects(componentType, L0.DomainOf))
72 if(graph.isSubrelationOf(relation, L0.HasProperty))
77 public static boolean isDomainOfRelation(ReadGraph graph,
78 Resource componentType, Resource connectionRelation) throws DatabaseException {
79 Layer0 L0 = Layer0.getInstance(graph);
80 for(Resource domain : graph.getObjects(connectionRelation, L0.HasDomain))
81 if(graph.isInheritedFrom(componentType, domain))
86 public static void addConnectionPoint(WriteGraph g, Resource componentType,
87 Resource connectionPoint) throws DatabaseException {
88 Layer0 L0 = Layer0.getInstance(g);
89 g.claim(connectionPoint, L0.HasDomain, componentType);
92 public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy) throws DatabaseException {
93 String proposition = NameUtils.getSafeName(g, copy);
94 String newName = NameUtils.findFreshName(g, proposition, componentType);
95 return createConnectionPoint(g, componentType, copy, newName);
98 public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException {
99 return createConnectionPointP(g, componentType, copy, name).first;
102 public static Pair<Resource,Resource> createConnectionPointP(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException {
104 Layer0 L0 = Layer0.getInstance(g);
105 StructuralResource2 STR = StructuralResource2.getInstance(g);
107 // Create the connection point
108 Resource connectionPoint = g.newResource();
109 Resource connectionPointInv = g.newResource();
111 for (Resource superrelation : g.getObjects(copy, L0.SubrelationOf)) {
112 g.claim(connectionPoint, L0.SubrelationOf, null, superrelation);
113 Resource inverse = g.getPossibleInverse(superrelation);
115 g.claim(connectionPointInv, L0.SubrelationOf, null, inverse);
117 for (Resource type : g.getObjects(copy, L0.InstanceOf)) {
118 g.claim(connectionPoint, L0.InstanceOf, null, type);
120 for (Resource attachment : g.getObjects(copy, STR.HasAttachmentRelation)) {
121 g.claim(connectionPoint, STR.HasAttachmentRelation, attachment);
123 for (Statement stm : g.getStatements(copy, STR.AllowsConnectionType)) {
124 if (!stm.isAsserted(copy)) {
125 g.claim(connectionPoint, stm.getPredicate(), stm.getObject());
129 g.claim(connectionPoint, L0.InverseOf, connectionPointInv);
130 g.claimLiteral(connectionPoint, L0.HasName, name, Bindings.STRING);
131 g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv);
132 g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING);
134 StructuralUtils.addConnectionPoint(g, componentType, connectionPoint);
136 g.claim(componentType, L0.ConsistsOf, connectionPoint);
138 return Pair.make(connectionPoint, connectionPointInv);
143 * Creates a new component and the templates associated with it.
144 * This method does not check whether there already exists
145 * a component with the same name and parent.
147 * @param parent The parent composite of the new component.
148 * @param name The name of the new component.
149 * @param componentType The type of the new component.
151 * @throws DatabaseException
153 public static Resource newComponent(WriteGraph g, Resource parent, String name, Resource componentType) throws DatabaseException {
154 Layer0 L0 = Layer0.getInstance(g);
156 HashMap<String,Object> parameters = new HashMap<String,Object>();
157 parameters.put("parent", parent);
159 InstantiateRequest ir = new InstantiateRequest(componentType, parameters);
160 Resource component = ir.perform(g);
161 g.claim(component, L0.HasName, Layer0Utils.literal(g, name));
162 g.claim(component, L0.HasLabel, Layer0Utils.literal(g, ""));
163 g.claim(parent, L0.ConsistsOf, component);
164 Layer0Utils.claimNewIdentifier(g, component, true);
165 // Add comment to change set.
166 CommentMetadata cm = g.getMetadata(CommentMetadata.class);
167 g.addMetadata(cm.add("Created component " + component));
172 * Returns all child components of a composite.
174 public static Collection<Resource> getChildComponents(ReadGraph g, Resource parent) throws DatabaseException {
175 Layer0 L0 = Layer0.getInstance(g);
176 StructuralResource2 STR = StructuralResource2.getInstance(g);
178 Collection<Resource> allChildren = g.getObjects(parent, L0.ConsistsOf);
179 ArrayList<Resource> result = new ArrayList<Resource>(allChildren.size());
180 for(Resource child : allChildren)
181 // Composite may contain other things than components, therefore we must do checking
182 if(g.isInstanceOf(child, STR.Component))
188 * Returns the component type of the given component or null if the
189 * parameter is not a component.
192 public static Resource getComponentType(ReadGraph g, Resource component) throws DatabaseException {
193 StructuralResource2 STR = StructuralResource2.getInstance(g);
194 return g.getPossibleType(component, STR.Component);
198 * Returns the definitions of the component type or null, if the component
199 * type does not have a definition.
201 public static Resource getComponentTypeDefinition(ReadGraph g, Resource componentType) throws DatabaseException {
202 StructuralResource2 STR = StructuralResource2.getInstance(g);
203 return g.getPossibleObject(componentType, STR.IsDefinedBy);
207 * Returns all (component,connectionRelation) pairs that are connected
208 * to the given component and connectionRelation.
210 * @param bindingRelation
213 public static Set<Terminal> getRelatedTerminals(RequestProcessor g, Resource component, Resource connectionRelation) throws DatabaseException {
214 return g.syncRequest(new ConnectedTo(component, connectionRelation));
218 * Returns all connections that are reachable from the given connection
219 * with IsJoinedBy-relation including the given connection itself.
221 public static Set<Resource> getRelatedConnections(RequestProcessor g, Resource connection) throws DatabaseException {
222 return g.syncRequest(new RelatedConnections(connection));
226 * Returns all connections that are reachable from the given connection join. *
228 public static Set<Resource> getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin) throws DatabaseException {
229 return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin));
233 * Returns all connections that are reachable from the given connection join
234 * without visiting the resources in the collection excludedConnections.
236 public static Set<Resource> getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin, Collection<Resource> excludedConnections) throws DatabaseException {
237 return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin, excludedConnections));
241 * Returns true if the given composite is a parent of some/all components
242 * where the connection is attached to.
244 public static boolean isConnectionInComposite(ReadGraph g, Resource connection, Resource composite) throws DatabaseException {
245 StructuralResource2 STR = StructuralResource2.getInstance(g);
246 Layer0 L0 = Layer0.getInstance(g);
247 Collection<Resource> connects = g.getObjects(connection, STR.Connects);
248 if (!connects.isEmpty()) {
249 for(Resource component : connects)
250 for(Resource parent : g.getObjects(component, L0.PartOf))
251 if(parent.equals(composite))
254 Set<Resource> joinedComposites = null;
255 for(Resource join : g.getObjects(connection, STR.IsJoinedBy)) {
256 Collection<Resource> joined = g.getObjects(join, STR.JoinsComposite);
257 if (joinedComposites == null) {
258 joinedComposites = new THashSet<Resource>(joined);
260 joinedComposites.retainAll(joined);
263 if (joinedComposites != null && joinedComposites.size() == 1) {
264 return joinedComposites.contains(composite);
270 public static Variable getConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
271 Layer0 L0 = Layer0.getInstance(graph);
272 String relationName = graph.getRelatedValue(relation, L0.HasName, Bindings.STRING);
273 return component.getProperty(graph, relationName);
276 public static Variable getPossibleConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
278 return getConnectionPoint(graph, component, relation);
279 } catch (MissingVariableException e) {
284 public static Variable getPossibleConnectionTo(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
285 Variable property = component.getPossibleProperty(graph, relation);
286 if(property == null) return null;
287 Connection conn = property.getPossibleValue(graph);
288 if(conn == null) return null;
289 Collection<Variable> cps = conn.getConnectionPoints(graph, component, null);
290 if(cps.size() == 2) {
291 for(Variable var : cps) {
292 if(property.equals(var)) continue;
299 public static boolean isImmutable(ReadGraph graph, Resource r) throws DatabaseException {
300 StructuralResource2 STR = StructuralResource2.getInstance(graph);
301 Resource uc = graph.syncRequest(new PossibleTypedParent(r, STR.ComponentType));
302 return graph.isImmutable(r)
303 // Anything under a published or locked user component is published as well
304 || (uc != null && (Layer0Utils.isPublished(graph, uc)
305 || graph.hasStatement(uc, STR.ComponentType_Locked)))
306 // Anything under a published container (shared library) is published as well
307 || Layer0Utils.isContainerPublished(graph, r)
311 public static List<Variable> structuralConnectionConnectionPoints(ReadGraph graph, Variable component, Connection conn, Resource relationType) throws DatabaseException {
312 return new ArrayList<Variable>(conn.getConnectionPoints(graph, component, relationType));
315 public static Resource structuralTypeResource(ReadGraph graph, Variable component, Resource baseType) throws DatabaseException {
317 if(component.getURI(graph).endsWith("/Alternative/Alternative/Panel2"))
318 System.err.println("structuralTypeResource " + component.getURI(graph));
320 StructuralOverrideData od = StructuralOverrideData.compute(graph, component);
323 // Resource represents = component.getPossibleRepresents(graph);
324 // if(represents == null) {
325 // String uri = component.getPossiblePropertyValue(graph, "typeURI");
326 // if(uri != null) return graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance());
327 // throw new DatabaseException("No type for " + component.getURI(graph));
329 // return graph.getPossibleType(represents, baseType);
331 // Pair<Resource,Resource> representsAndType = graph.syncRequest(new PossibleRepresentsAndTypeWithOverrides(component));
332 // return representsAndType.second;
336 public static Resource getComponentType(ReadGraph graph, Variable configuration, Resource component) throws DatabaseException {
338 Variable componentVariable = configuration.browse(graph, component);
339 return componentVariable.getType(graph);