1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.structural2.utils;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.List;
20 import org.simantics.databoard.Bindings;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.RequestProcessor;
23 import org.simantics.db.Resource;
24 import org.simantics.db.Statement;
25 import org.simantics.db.WriteGraph;
26 import org.simantics.db.common.CommentMetadata;
27 import org.simantics.db.common.request.ObjectsWithType;
28 import org.simantics.db.common.request.PossibleTypedParent;
29 import org.simantics.db.common.utils.NameUtils;
30 import org.simantics.db.exception.DatabaseException;
31 import org.simantics.db.layer0.exception.MissingVariableException;
32 import org.simantics.db.layer0.request.InstantiateRequest;
33 import org.simantics.db.layer0.util.Layer0Utils;
34 import org.simantics.db.layer0.variable.Variable;
35 import org.simantics.layer0.Layer0;
36 import org.simantics.structural.stubs.StructuralResource2;
37 import org.simantics.structural2.Functions.StructuralOverrideData;
38 import org.simantics.structural2.internal.queries.ConnectedTo;
39 import org.simantics.structural2.internal.queries.RelatedConnections;
40 import org.simantics.structural2.internal.queries.RelatedConnectionsOfConnectionJoin;
41 import org.simantics.structural2.queries.Terminal;
42 import org.simantics.structural2.variables.Connection;
43 import org.simantics.utils.datastructures.Pair;
45 import gnu.trove.set.hash.THashSet;
48 * A utility class for manipulating structural models.
50 * @author Hannu Niemistö
52 public class StructuralUtils {
54 public static enum StructuralComponentClass {
56 PRIMITIVE,REPLACEABLE,DEFINED,PROCEDURAL;
58 public static StructuralComponentClass get(ReadGraph graph, Resource componentType) throws DatabaseException {
59 StructuralResource2 STR = StructuralResource2.getInstance(graph);
60 Set<Resource> types = graph.getTypes(componentType);
61 if(types.contains(STR.ProceduralComponentType))
62 return StructuralComponentClass.PROCEDURAL;
63 else if(graph.hasStatement(componentType, STR.IsDefinedBy))
64 return StructuralComponentClass.DEFINED;
65 else if(types.contains(STR.ReplaceableDefinedComponentType))
66 return StructuralComponentClass.REPLACEABLE;
68 return StructuralComponentClass.PRIMITIVE;
73 public static Collection<Resource> getConnectionRelations(ReadGraph graph, Resource componentType) throws DatabaseException {
74 Layer0 L0 = Layer0.getInstance(graph);
75 StructuralResource2 STR = StructuralResource2.getInstance(graph);
76 return graph.syncRequest(new ObjectsWithType(componentType, L0.DomainOf, STR.ConnectionRelation));
79 public static Collection<Resource> getPropertyRelations(ReadGraph graph, Resource componentType) throws DatabaseException {
80 Layer0 L0 = Layer0.getInstance(graph);
81 ArrayList<Resource> result = new ArrayList<Resource>();
82 for(Resource relation : graph.getObjects(componentType, L0.DomainOf))
83 if(graph.isSubrelationOf(relation, L0.HasProperty))
88 public static boolean isDomainOfRelation(ReadGraph graph,
89 Resource componentType, Resource connectionRelation) throws DatabaseException {
90 Layer0 L0 = Layer0.getInstance(graph);
91 for(Resource domain : graph.getObjects(connectionRelation, L0.HasDomain))
92 if(graph.isInheritedFrom(componentType, domain))
97 public static void addConnectionPoint(WriteGraph g, Resource componentType,
98 Resource connectionPoint) throws DatabaseException {
99 Layer0 L0 = Layer0.getInstance(g);
100 g.claim(connectionPoint, L0.HasDomain, componentType);
103 public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy) throws DatabaseException {
104 String proposition = NameUtils.getSafeName(g, copy);
105 String newName = NameUtils.findFreshName(g, proposition, componentType);
106 return createConnectionPoint(g, componentType, copy, newName);
109 public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException {
110 return createConnectionPointP(g, componentType, copy, name).first;
113 public static Pair<Resource,Resource> createConnectionPointP(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException {
115 Layer0 L0 = Layer0.getInstance(g);
116 StructuralResource2 STR = StructuralResource2.getInstance(g);
118 // Create the connection point
119 Resource connectionPoint = g.newResource();
120 Resource connectionPointInv = g.newResource();
122 for (Resource superrelation : g.getObjects(copy, L0.SubrelationOf)) {
123 g.claim(connectionPoint, L0.SubrelationOf, null, superrelation);
124 Resource inverse = g.getPossibleInverse(superrelation);
126 g.claim(connectionPointInv, L0.SubrelationOf, null, inverse);
128 for (Resource type : g.getObjects(copy, L0.InstanceOf)) {
129 g.claim(connectionPoint, L0.InstanceOf, null, type);
131 for (Resource attachment : g.getObjects(copy, STR.HasAttachmentRelation)) {
132 g.claim(connectionPoint, STR.HasAttachmentRelation, attachment);
134 for (Statement stm : g.getStatements(copy, STR.AllowsConnectionType)) {
135 if (!stm.isAsserted(copy)) {
136 g.claim(connectionPoint, stm.getPredicate(), stm.getObject());
140 g.claim(connectionPoint, L0.InverseOf, connectionPointInv);
141 g.claimLiteral(connectionPoint, L0.HasName, name, Bindings.STRING);
142 g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv);
143 g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING);
145 StructuralUtils.addConnectionPoint(g, componentType, connectionPoint);
147 g.claim(componentType, L0.ConsistsOf, connectionPoint);
149 return Pair.make(connectionPoint, connectionPointInv);
154 * Creates a new component and the templates associated with it.
155 * This method does not check whether there already exists
156 * a component with the same name and parent.
158 * @param parent The parent composite of the new component.
159 * @param name The name of the new component.
160 * @param componentType The type of the new component.
162 * @throws DatabaseException
164 public static Resource newComponent(WriteGraph g, Resource parent, String name, Resource componentType) throws DatabaseException {
165 Layer0 L0 = Layer0.getInstance(g);
167 HashMap<String,Object> parameters = new HashMap<String,Object>();
168 parameters.put("parent", parent);
170 InstantiateRequest ir = new InstantiateRequest(componentType, parameters);
171 Resource component = ir.perform(g);
172 g.claim(component, L0.HasName, Layer0Utils.literal(g, name));
173 g.claim(component, L0.HasLabel, Layer0Utils.literal(g, ""));
174 g.claim(parent, L0.ConsistsOf, component);
175 Layer0Utils.claimNewIdentifier(g, component, true);
176 // Add comment to change set.
177 CommentMetadata cm = g.getMetadata(CommentMetadata.class);
178 g.addMetadata(cm.add("Created component " + component));
183 * Returns all child components of a composite.
185 public static Collection<Resource> getChildComponents(ReadGraph g, Resource parent) throws DatabaseException {
186 Layer0 L0 = Layer0.getInstance(g);
187 StructuralResource2 STR = StructuralResource2.getInstance(g);
189 Collection<Resource> allChildren = g.getObjects(parent, L0.ConsistsOf);
190 ArrayList<Resource> result = new ArrayList<Resource>(allChildren.size());
191 for(Resource child : allChildren)
192 // Composite may contain other things than components, therefore we must do checking
193 if(g.isInstanceOf(child, STR.Component))
199 * Returns the component type of the given component or null if the
200 * parameter is not a component.
203 public static Resource getComponentType(ReadGraph g, Resource component) throws DatabaseException {
204 StructuralResource2 STR = StructuralResource2.getInstance(g);
205 return g.getPossibleType(component, STR.Component);
209 * Returns the definitions of the component type or null, if the component
210 * type does not have a definition.
212 public static Resource getComponentTypeDefinition(ReadGraph g, Resource componentType) throws DatabaseException {
213 StructuralResource2 STR = StructuralResource2.getInstance(g);
214 return g.getPossibleObject(componentType, STR.IsDefinedBy);
218 * Returns all (component,connectionRelation) pairs that are connected
219 * to the given component and connectionRelation.
221 * @param bindingRelation
224 public static Set<Terminal> getRelatedTerminals(RequestProcessor g, Resource component, Resource connectionRelation) throws DatabaseException {
225 return g.syncRequest(new ConnectedTo(component, connectionRelation));
229 * Returns all connections that are reachable from the given connection
230 * with IsJoinedBy-relation including the given connection itself.
232 public static Set<Resource> getRelatedConnections(RequestProcessor g, Resource connection) throws DatabaseException {
233 return g.syncRequest(new RelatedConnections(connection));
237 * Returns all connections that are reachable from the given connection join. *
239 public static Set<Resource> getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin) throws DatabaseException {
240 return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin));
244 * Returns all connections that are reachable from the given connection join
245 * without visiting the resources in the collection excludedConnections.
247 public static Set<Resource> getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin, Collection<Resource> excludedConnections) throws DatabaseException {
248 return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin, excludedConnections));
252 * Returns true if the given composite is a parent of some/all components
253 * where the connection is attached to.
255 public static boolean isConnectionInComposite(ReadGraph g, Resource connection, Resource composite) throws DatabaseException {
256 StructuralResource2 STR = StructuralResource2.getInstance(g);
257 Layer0 L0 = Layer0.getInstance(g);
258 Collection<Resource> connects = g.getObjects(connection, STR.Connects);
259 if (!connects.isEmpty()) {
260 for(Resource component : connects)
261 for(Resource parent : g.getObjects(component, L0.PartOf))
262 if(parent.equals(composite))
265 Set<Resource> joinedComposites = null;
266 for(Resource join : g.getObjects(connection, STR.IsJoinedBy)) {
267 Collection<Resource> joined = g.getObjects(join, STR.JoinsComposite);
268 if (joinedComposites == null) {
269 joinedComposites = new THashSet<Resource>(joined);
271 joinedComposites.retainAll(joined);
274 if (joinedComposites != null && joinedComposites.size() == 1) {
275 return joinedComposites.contains(composite);
281 public static Variable getConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
282 Layer0 L0 = Layer0.getInstance(graph);
283 String relationName = graph.getRelatedValue(relation, L0.HasName, Bindings.STRING);
284 return component.getProperty(graph, relationName);
287 public static Variable getPossibleConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
289 return getConnectionPoint(graph, component, relation);
290 } catch (MissingVariableException e) {
295 public static Variable getPossibleConnectionTo(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
296 Variable property = component.getPossibleProperty(graph, relation);
297 if(property == null) return null;
298 Connection conn = property.getPossibleValue(graph);
299 if(conn == null) return null;
300 Collection<Variable> cps = conn.getConnectionPoints(graph, null);
301 if(cps.size() == 2) {
302 for(Variable var : cps) {
303 if(property.equals(var)) continue;
310 public static boolean isImmutable(ReadGraph graph, Resource r) throws DatabaseException {
311 // Marking a resource L0.readOnly also makes it immutable
312 if (graph.isImmutable(r) || Layer0Utils.isMarkedReadOnly(graph, r))
314 StructuralResource2 STR = StructuralResource2.getInstance(graph);
315 Resource uc = graph.syncRequest(new PossibleTypedParent(r, STR.ComponentType));
316 return // Anything under a published or locked user component is published as well
317 (uc != null && (Layer0Utils.isPublished(graph, uc)
318 || graph.hasStatement(uc, STR.ComponentType_Locked)))
319 // Anything under a published container (shared library) is published as well
320 || Layer0Utils.isContainerPublished(graph, r)
324 public static List<Variable> structuralConnectionConnectionPoints(ReadGraph graph, Connection conn, Resource relationType) throws DatabaseException {
325 return new ArrayList<Variable>(conn.getConnectionPoints(graph, relationType));
328 public static Resource structuralTypeResource(ReadGraph graph, Variable component, Resource baseType) throws DatabaseException {
329 StructuralOverrideData od = StructuralOverrideData.compute(graph, component);
335 public static Resource getComponentType(ReadGraph graph, Variable configuration, Resource component) throws DatabaseException {
336 Variable componentVariable = configuration.browse(graph, component);
337 return componentVariable.getType(graph);
340 public static Resource getPossibleComponentType(ReadGraph graph, Variable configuration, Resource component) throws DatabaseException {
341 Variable componentVariable = configuration.browsePossible(graph, component);
342 if(componentVariable == null) return null;
343 StructuralResource2 STR = StructuralResource2.getInstance(graph);
344 return componentVariable.getPossibleType(graph, STR.Component);