9f5897f06a24d476a44d2b4424ac7d58444170a8
[simantics/platform.git] / bundles / org.simantics.structural2 / src / org / simantics / structural2 / utils / StructuralUtils.java
1 package org.simantics.structural2.utils;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Set;
8
9 import org.simantics.databoard.Bindings;
10 import org.simantics.datatypes.literal.GUID;
11 import org.simantics.db.ReadGraph;
12 import org.simantics.db.RequestProcessor;
13 import org.simantics.db.Resource;
14 import org.simantics.db.Statement;
15 import org.simantics.db.WriteGraph;
16 import org.simantics.db.common.CommentMetadata;
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.internal.queries.ConnectedTo;
28 import org.simantics.structural2.internal.queries.RelatedConnections;
29 import org.simantics.structural2.internal.queries.RelatedConnectionsOfConnectionJoin;
30 import org.simantics.structural2.queries.Terminal;
31 import org.simantics.structural2.variables.Connection;
32 import org.simantics.utils.datastructures.Pair;
33
34 import gnu.trove.set.hash.THashSet;
35
36 /**
37  * A utility class for manipulating structural models.
38  * 
39  * @author Hannu Niemistö
40  */
41 public class StructuralUtils {
42     
43     public static Collection<Resource> getConnectionRelations(ReadGraph graph, Resource componentType) throws DatabaseException {
44         Layer0 L0 = Layer0.getInstance(graph);
45         StructuralResource2 STR = StructuralResource2.getInstance(graph);
46         return graph.syncRequest(new ObjectsWithType(componentType, L0.DomainOf, STR.ConnectionRelation));
47     }
48
49     public static Collection<Resource> getPropertyRelations(ReadGraph graph, Resource componentType) throws DatabaseException {
50         Layer0 L0 = Layer0.getInstance(graph);
51         ArrayList<Resource> result = new ArrayList<Resource>();
52         for(Resource relation : graph.getObjects(componentType, L0.DomainOf))
53             if(graph.isSubrelationOf(relation, L0.HasProperty))
54                 result.add(relation);
55         return result;
56     }
57     
58     public static boolean isDomainOfRelation(ReadGraph graph,
59             Resource componentType, Resource connectionRelation) throws DatabaseException {
60         Layer0 L0 = Layer0.getInstance(graph);
61         for(Resource domain : graph.getObjects(connectionRelation, L0.HasDomain))
62             if(graph.isInheritedFrom(componentType, domain))
63                 return true;
64         return false;
65     }
66     
67     public static void addConnectionPoint(WriteGraph g, Resource componentType,
68             Resource connectionPoint) throws DatabaseException {
69         Layer0 L0 = Layer0.getInstance(g);
70         g.claim(connectionPoint, L0.HasDomain, componentType);
71     }
72     
73     public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy) throws DatabaseException {
74         String proposition = NameUtils.getSafeName(g, copy);
75         String newName = NameUtils.findFreshName(g, proposition, componentType);
76         return createConnectionPoint(g, componentType, copy, newName);
77     }
78     
79     public static Resource createConnectionPoint(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException {
80         return createConnectionPointP(g, componentType, copy, name).first;
81     }
82     
83     public static Pair<Resource,Resource> createConnectionPointP(WriteGraph g, Resource componentType, Resource copy, String name) throws DatabaseException {
84         
85         Layer0 L0 = Layer0.getInstance(g);
86         StructuralResource2 STR = StructuralResource2.getInstance(g);
87
88         // Create the connection point
89         Resource connectionPoint = g.newResource();
90         Resource connectionPointInv = g.newResource();
91
92         for (Resource superrelation : g.getObjects(copy, L0.SubrelationOf)) {
93             g.claim(connectionPoint, L0.SubrelationOf, null, superrelation);
94             Resource inverse = g.getPossibleInverse(superrelation);
95             if (inverse != null)
96                 g.claim(connectionPointInv, L0.SubrelationOf, null, inverse);
97         }
98         for (Resource type : g.getObjects(copy, L0.InstanceOf)) {
99             g.claim(connectionPoint, L0.InstanceOf, null, type);
100         }
101         for (Resource attachment : g.getObjects(copy, STR.HasAttachmentRelation)) {
102             g.claim(connectionPoint, STR.HasAttachmentRelation, attachment);
103         }
104         for (Statement stm : g.getStatements(copy, STR.AllowsConnectionType)) {
105             if (!stm.isAsserted(copy)) {
106                 g.claim(connectionPoint, stm.getPredicate(), stm.getObject());
107             }
108         }
109
110         g.claim(connectionPoint, L0.InverseOf, connectionPointInv);
111         g.claimLiteral(connectionPoint, L0.HasName, name, Bindings.STRING);
112         g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv);
113         g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING);
114
115         StructuralUtils.addConnectionPoint(g, componentType, connectionPoint);
116
117         g.claim(componentType, L0.ConsistsOf, connectionPoint);
118
119         return Pair.make(connectionPoint, connectionPointInv);
120         
121     }
122
123     /**
124      * Creates a new component and the templates associated with it.
125      * This method does not check whether there already exists 
126      * a component with the same name and parent.
127      * @param g
128      * @param parent The parent composite of the new component.
129      * @param name The name of the new component.
130      * @param componentType The type of the new component.
131      * @return
132      * @throws DatabaseException
133      */
134     public static Resource newComponent(WriteGraph g, Resource parent, String name, Resource componentType) throws DatabaseException {
135         Layer0 L0 = Layer0.getInstance(g);
136         
137         HashMap<String,Object> parameters = new HashMap<String,Object>();
138         parameters.put("parent", parent);
139
140         InstantiateRequest ir = new InstantiateRequest(componentType, parameters);
141         Resource component = ir.perform(g);        
142         g.claim(component, L0.HasName, Layer0Utils.literal(g, name));
143         g.claim(component, L0.HasLabel, Layer0Utils.literal(g, ""));
144         g.addLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, GUID.random(), GUID.BINDING);
145         g.claim(parent, L0.ConsistsOf, component);
146         // Add comment to change set.
147         CommentMetadata cm = g.getMetadata(CommentMetadata.class);
148         g.addMetadata(cm.add("Created component " + component));
149         return component;
150     }
151     
152     /**
153      * Returns all child components of a composite.
154      */
155     public static Collection<Resource> getChildComponents(ReadGraph g, Resource parent) throws DatabaseException {
156         Layer0 L0 = Layer0.getInstance(g);
157         StructuralResource2 STR = StructuralResource2.getInstance(g);
158         
159         Collection<Resource> allChildren = g.getObjects(parent, L0.ConsistsOf);
160         ArrayList<Resource> result = new ArrayList<Resource>(allChildren.size());
161         for(Resource child : allChildren)
162             // Composite may contain other things than components, therefore we must do checking
163             if(g.isInstanceOf(child, STR.Component))
164                 result.add(child);
165         return result;
166     }
167
168     /**
169      * Returns the component type of the given component or null if the 
170      * parameter is not a component.
171      */
172     public static Resource getComponentType(ReadGraph g, Resource component) throws DatabaseException {
173         StructuralResource2 STR = StructuralResource2.getInstance(g);
174         return g.getPossibleType(component, STR.Component);
175     }
176     
177     /**
178      * Returns the definitions of the component type or null, if the component
179      * type does not have a definition.
180      */
181     public static Resource getComponentTypeDefinition(ReadGraph g, Resource componentType) throws DatabaseException {
182         StructuralResource2 STR = StructuralResource2.getInstance(g);
183         return g.getPossibleObject(componentType, STR.IsDefinedBy);
184     }
185     
186     /**
187      * Returns all (component,connectionRelation) pairs that are connected
188      * to the given component and connectionRelation.
189      * @param component
190      * @param bindingRelation
191      * @return
192      */
193     public static Set<Terminal> getRelatedTerminals(RequestProcessor g, Resource component, Resource connectionRelation) throws DatabaseException {
194         return g.syncRequest(new ConnectedTo(component, connectionRelation));
195     }
196     
197     /**
198      * Returns all connections that are reachable from the given connection
199      * with IsJoinedBy-relation including the given connection itself. 
200      */ 
201     public static Set<Resource> getRelatedConnections(RequestProcessor g, Resource connection) throws DatabaseException {
202         return g.syncRequest(new RelatedConnections(connection));
203     }
204     
205     /**
206      * Returns all connections that are reachable from the given connection join.     * 
207      */ 
208     public static Set<Resource> getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin) throws DatabaseException {
209         return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin));
210     }
211     
212     /**
213      * Returns all connections that are reachable from the given connection join
214      * without visiting the resources in the collection excludedConnections.
215      */
216     public static Set<Resource> getRelatedConnectionsOfConnectionJoin(RequestProcessor g, Resource connectionJoin, Collection<Resource> excludedConnections) throws DatabaseException {
217         return g.syncRequest(new RelatedConnectionsOfConnectionJoin(connectionJoin, excludedConnections));
218     }
219     
220     /**
221      * Returns true if the given composite is a parent of some/all components 
222      * where the connection is attached to.
223      */
224     public static boolean isConnectionInComposite(ReadGraph g, Resource connection, Resource composite) throws DatabaseException {
225         StructuralResource2 STR = StructuralResource2.getInstance(g);
226         Layer0 L0 = Layer0.getInstance(g);
227         Collection<Resource> connects = g.getObjects(connection, STR.Connects);
228         if (!connects.isEmpty()) {
229             for(Resource component : connects)
230                 for(Resource parent : g.getObjects(component, L0.PartOf))
231                     if(parent.equals(composite))
232                         return true;
233         } else {
234             Set<Resource> joinedComposites = null;
235             for(Resource join : g.getObjects(connection, STR.IsJoinedBy)) {
236                 Collection<Resource> joined = g.getObjects(join, STR.JoinsComposite);
237                 if (joinedComposites == null) {
238                     joinedComposites = new THashSet<Resource>(joined);
239                 } else {
240                     joinedComposites.retainAll(joined);
241                 }
242             }
243             if (joinedComposites != null && joinedComposites.size() == 1) {
244                 return joinedComposites.contains(composite);
245             }
246         }
247         return false;
248     }
249     
250     public static Variable getConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
251         Layer0 L0 = Layer0.getInstance(graph);
252         String relationName = graph.getRelatedValue(relation, L0.HasName, Bindings.STRING);
253         return component.getProperty(graph, relationName);
254     }
255
256     public static Variable getPossibleConnectionPoint(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
257         try {
258                 return getConnectionPoint(graph, component, relation);
259         } catch (MissingVariableException e) {
260                 return null;
261         }
262     }
263
264     public static Variable getPossibleConnectionTo(ReadGraph graph, Variable component, Resource relation) throws DatabaseException {
265         Variable property = component.getPossibleProperty(graph, relation);
266         if(property == null) return null;
267         Connection conn = property.getPossibleValue(graph);
268         if(conn == null) return null;
269         Collection<Variable> cps = conn.getConnectionPoints(graph, null);
270         if(cps.size() == 2) {
271                 for(Variable var : cps) {
272                         if(property.equals(var)) continue;
273                         return var;
274                 }
275         }
276         return null;
277     }
278
279     public static boolean isImmutable(ReadGraph graph, Resource r) throws DatabaseException {
280         StructuralResource2 STR = StructuralResource2.getInstance(graph);
281         Resource uc = graph.syncRequest(new PossibleTypedParent(r, STR.ComponentType));
282         return graph.isImmutable(r)
283                 // Anything under a published or locked user component is published as well
284                 || (uc != null && (Layer0Utils.isPublished(graph, uc)
285                          || graph.hasStatement(uc, STR.ComponentType_Locked)))
286                 // Anything under a published container (shared library) is published as well
287                 || Layer0Utils.isContainerPublished(graph, r)
288                 ;
289     }
290     
291     public static List<Variable> structuralConnectionConnectionPoints(ReadGraph graph, Connection conn, Resource relationType) throws DatabaseException {
292         return new ArrayList<Variable>(conn.getConnectionPoints(graph, relationType));
293     }
294
295 }