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