Improvements to resolving primitive properties in document server
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / DocumentServerUtils.java
1 package org.simantics.document.server;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.SortedMap;
10 import java.util.TreeMap;
11
12 import org.simantics.databoard.Bindings;
13 import org.simantics.db.ReadGraph;
14 import org.simantics.db.Resource;
15 import org.simantics.db.common.request.UnaryRead;
16 import org.simantics.db.exception.DatabaseException;
17 import org.simantics.db.layer0.request.VariableRead;
18 import org.simantics.db.layer0.variable.ProxyChildVariable;
19 import org.simantics.db.layer0.variable.Variable;
20 import org.simantics.db.layer0.variable.Variables;
21 import org.simantics.document.base.ontology.DocumentationResource;
22 import org.simantics.document.server.Functions.RootVariable;
23 import org.simantics.document.server.request.NodeRequest;
24 import org.simantics.document.server.request.NodeRequestUtils;
25 import org.simantics.structural2.variables.Connection;
26 import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
27 import org.simantics.utils.datastructures.Pair;
28 import org.simantics.utils.strings.AlphanumComparator;
29
30 public class DocumentServerUtils {
31
32     public static Collection<Variable> getChildren(ReadGraph graph, Variable variable) throws DatabaseException {
33
34         DocumentationResource DOC = DocumentationResource.getInstance(graph);
35         
36                 ArrayList<Variable> result = new ArrayList<Variable>();
37                 for(Variable property : variable.getProperties(graph)) {
38                         Collection<String> classifications = property.getPossiblePropertyValue(graph, Variables.CLASSIFICATIONS);
39                         if(classifications != null) {
40                                 if(classifications.contains(DocumentationResource.URIs.Document_ChildRelation)) {
41                                         Connection conn = property.getValue(graph);
42                                         Variable childConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, property, conn);
43                                         if(childConnectionPoint != null) {
44                                                 result.add(childConnectionPoint.getParent(graph));
45                                         }
46                                 } else if (DOC.Relations_partN.equals(property.getPossiblePredicateResource(graph))) {
47                                         Connection conn = property.getValue(graph);
48                                         for (Variable childConnectionPoint : DocumentServerUtils.getOtherConnectionPoints(graph, property, conn)) {
49                                                 result.add(childConnectionPoint.getParent(graph));
50                                         }
51                                 }
52                         }
53                 }
54                 return result;
55
56         }
57     
58         public static String findManualOrdinal(ReadGraph graph, Variable v) throws DatabaseException {
59                 DocumentationResource DOC = DocumentationResource.getInstance(graph);
60                 Integer j = null;
61                 while (j == null && v != null) {
62                         j = v.getPossiblePropertyValue(graph, DOC.Components_Component_manualOrdinal);
63                         v = v.getParent(graph);
64                 }
65                 if (j != null) {
66                         return Integer.toString(j);
67                 } else {
68                         return null;
69                 }
70         }
71     
72     public static Collection<Variable> getChildrenInOrdinalOrder(ReadGraph graph, Variable variable) throws DatabaseException {
73         DocumentationResource DOC = DocumentationResource.getInstance(graph);
74         
75                 SortedMap<String, Variable> childMap = new TreeMap<String, Variable>(AlphanumComparator.COMPARATOR);
76                 
77                 for(Variable property : variable.getProperties(graph, DocumentationResource.URIs.Document_ChildRelation)) {
78                         Resource cp = property.getPossiblePredicateResource(graph);
79                         String i = graph.getRelatedValue(cp, DOC.Document_ChildRelation_ordinal, Bindings.STRING);
80                         Connection conn = property.getValue(graph);
81                         Variable childConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, property, conn);
82                         if(childConnectionPoint != null) {
83                                 childMap.put(i, childConnectionPoint.getParent(graph));
84                         }
85                 }
86                 
87                 Variable property = variable.getPossibleProperty(graph, "partN");
88                 if(property != null) {
89                         Connection conn = property.getValue(graph);
90                         for (Variable childConnectionPoint : DocumentServerUtils.getOtherConnectionPoints(graph, property, conn)) {
91                                 Variable child = childConnectionPoint.getParent(graph);
92                                 String i = findManualOrdinal(graph, child);
93                                 if (i == null) {
94                                         i = "0";
95                                 }
96                                 childMap.put(i, child);
97                         }
98                 }
99
100                 return childMap.values();
101
102         }    
103
104         public static Collection<Variable> collectNodes(ReadGraph graph, Variable variable, Collection<Variable> nodes) throws DatabaseException {
105
106                 DocumentationResource DOC = DocumentationResource.getInstance(graph);
107
108                 Resource type = variable.getPossibleType(graph);
109                 if(type == null) return nodes;
110                 
111                 if(!graph.isInheritedFrom(type, DOC.Components_Component)) return nodes;
112
113                 Boolean enabled = variable.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);
114                 if(enabled != null && !enabled) return nodes;
115
116                 if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {
117                         nodes.add(variable);
118                 } else {
119                         for(Variable child : variable.getChildren(graph)) {
120                                 collectNodes(graph, child, nodes);
121                         }
122                 }
123
124                 return nodes;
125
126         }
127
128         public static Variable getPossibleOtherConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
129
130                 Collection<VariableConnectionPointDescriptor> descs = conn.getConnectionPointDescriptors(graph, null);
131                 if(descs.size() != 2) return null;
132
133                 for(VariableConnectionPointDescriptor desc : descs) {
134                         if(desc.isFlattenedFrom(graph, connectionPoint)) continue;
135                         return desc.getVariable(graph);
136                 }
137                 
138                 return null;
139
140         }
141
142         public static Variable getPossibleChildConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
143
144                 Collection<VariableConnectionPointDescriptor> descs = conn.getConnectionPointDescriptors(graph, null);
145                 if(descs.size() != 2) return null;
146
147         DocumentationResource DOC = DocumentationResource.getInstance(graph);
148                 
149                 for(VariableConnectionPointDescriptor desc : descs) {
150                         Resource res = desc.getConnectionPointResource(graph);
151                         if(graph.isInstanceOf(res, DOC.Relations_parentRelation)) continue;
152                         //if(desc.isFlattenedFrom(graph, connectionPoint)) continue;
153                         return desc.getVariable(graph);
154                 }
155                 
156                 return null;
157
158         }
159         
160         public static Collection<Variable> getOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
161
162                 ArrayList<Variable> connectionPoints = new ArrayList<Variable>();
163                 
164                 Collection<VariableConnectionPointDescriptor> descs = conn.getConnectionPointDescriptors(graph, null);
165
166                 for(VariableConnectionPointDescriptor desc : descs) {
167                         if(desc.isFlattenedFrom(graph, connectionPoint)) continue;
168                         connectionPoints.add(desc.getVariable(graph));
169                 }
170                 
171                 return connectionPoints;
172
173         }
174
175         public static Variable getPossibleCommandTriggerConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
176
177                 Collection<Variable> cpts = conn.getConnectionPoints(graph, null);
178
179                 Variable result = null;
180                 
181                 for(Variable cpt : cpts) {
182                         Set<String> classifications = cpt.getClassifications(graph);
183                         if(classifications.contains(DocumentationResource.URIs.Relations_commandExecutorRelation)) {
184                                 if(result != null) throw new DatabaseException("Multiple executor connection points in command connection");
185                                 result = cpt;
186                         }
187                 }
188                 
189                 return result;
190
191         }
192
193         public static Collection<Variable> getPossibleOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
194
195             Collection<Variable> cpts = conn.getConnectionPoints(graph, null);
196             if(cpts.size() < 2) 
197                 return Collections.emptyList();
198
199             ArrayList<Variable> result = new ArrayList<Variable>();
200             for(Variable cpt : cpts) {
201                 if(!cpt.equals(connectionPoint)) 
202                     result.add(cpt);
203             }
204             return result;
205         }
206
207         public static String getId(ReadGraph graph, Variable node) throws DatabaseException {
208
209                 if(node == null) return "root";
210                 else {
211                         String uri = node.getURI(graph); 
212                         int l = uri.lastIndexOf(ProxyChildVariable.CONTEXT_END);
213                         return uri.substring(l+4);
214                 }
215
216         }
217
218         public static Object getValue(ReadGraph graph, Variable attrib) throws DatabaseException {
219                 return graph.syncRequest(new DocumentValue(attrib));
220         }
221
222         public static Variable getParentConnectionPoint(ReadGraph graph, Variable component) throws DatabaseException {
223
224                 Variable connectionPoint = component.getPossibleProperty(graph, "parent");
225                 if(connectionPoint == null) {
226                         DocumentationResource DOC = DocumentationResource.getInstance(graph);
227                         Collection<Variable> cps = component.getProperties(graph, DOC.Relations_parentRelation);
228                         if(cps.size() == 1) {
229                                 connectionPoint = cps.iterator().next();
230                         } else {
231                                 return null;
232                         }
233                 }
234                 
235                 Connection conn = connectionPoint.getValue(graph);
236                 Variable otherCp = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, connectionPoint, conn);
237                 if (otherCp != null) {
238                         return otherCp;
239                 } else {
240                         Variable parentCp = graph.sync(new UnaryRead<Connection, Variable>(conn) {
241                     @Override
242                     public Variable perform(ReadGraph graph) throws DatabaseException {
243                         DocumentationResource DOC = DocumentationResource.getInstance(graph);
244                         Collection<VariableConnectionPointDescriptor> descs = parameter.getConnectionPointDescriptors(graph, null);
245
246                                 for(VariableConnectionPointDescriptor desc : descs) {
247                                         if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {
248                                                 return desc.getVariable(graph);
249                                         }
250                                 }
251                                 return null;
252                     }
253                 });
254                         if (parentCp != null) {
255                                 return parentCp;
256                         }
257                 }
258                 return null;
259
260         }
261         
262         /* Children */
263         public static Collection<Variable> getChildConnections(ReadGraph graph, Variable variable) throws DatabaseException {
264                 return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_ChildRelation);
265         }
266
267         /* Command sequence */
268         public static Collection<Variable> getTriggerCommands(ReadGraph graph, Variable variable) throws DatabaseException {
269                 ArrayList<Variable> result = new ArrayList<Variable>();
270                 DocumentationResource DOC = DocumentationResource.getInstance(graph);
271                 for(Variable var : variable.getProperties(graph, DOC.Document_CommandRelation)) {
272             if(DOC.Relations_broadcasted.equals(var.getPredicateResource(graph))) continue;
273             result.add(var);
274                 }
275                 return result;
276         }
277
278         public static Collection<Variable> getCommands(ReadGraph graph, Variable variable) throws DatabaseException {
279                 return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_CommandRelation);
280         }
281
282         /* Data definition */
283         public static Collection<Variable> getDataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException {
284                 return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_DataDefinitionRelation);
285         }
286
287         /* Data relation */
288         public static Collection<Variable> getDataRelations(ReadGraph graph, Variable variable) throws DatabaseException {
289                 return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_DataRelation);
290         }
291
292         /* Attributes */
293         public static Collection<Variable> getAttributes(ReadGraph graph, DocumentationResource DOC, Variable variable) throws DatabaseException {
294                 return variable.getProperties(graph, DOC.Document_AttributeRelation);
295         }
296         
297         public static class AttributesRequest extends VariableRead<Pair<JSONObject, Collection<Variable>>> {
298
299                 public AttributesRequest(Variable variable) {
300                         super(variable);
301                 }
302
303                 @Override
304                 public Pair<JSONObject,Collection<Variable>> perform(ReadGraph graph) throws DatabaseException {
305                 ArrayList<Variable> statics = new ArrayList<Variable>();
306                 DocumentationResource DOC = DocumentationResource.getInstance(graph);
307                 
308                 Variable primitives = variable.getProperty(graph, DOC.Properties_primitiveProperties);
309                 for(Variable property : primitives.getProperties(graph)) {
310                         statics.add(property);
311                         // NO SUPPORT FOR DYNAMICS AT THIS STAGE
312                 }
313                 
314                 JSONObject staticContent = computeStatic(graph, variable, statics);
315                 
316                 return new Pair<JSONObject, Collection<Variable>>(staticContent, Collections.emptyList());
317                 
318                 }
319                 
320                 JSONObject computeStatic(ReadGraph graph, Variable variable, ArrayList<Variable> statics) throws DatabaseException {
321                         
322                         JSONObject base = graph.syncRequest(new org.simantics.document.server.request.DefaultFields(variable));
323                         JSONObject object = base.clone();
324                         
325                         for(Variable attrib : statics) {
326                                 String name = attrib.getName(graph);
327                                 try {
328                                         if (name.equals(NodeRequest.PROPERTY_VALUE_EXCEPTIONS)) {
329                                         @SuppressWarnings("unchecked")
330                                                 Map<String, Exception> exceptions = (Map<String, Exception>)DocumentServerUtils.getValue(graph, attrib);
331                                         
332                                         List<String> errorList = object.getJSONField(NodeRequest.ERRORS);
333                                             if(errorList == null)
334                                                 errorList = new ArrayList<String>();
335                                             
336                                     for (Map.Entry<String, Exception> entry : exceptions.entrySet()) {
337                                         String errorMessage = NodeRequestUtils.formatErrorMessage(entry.getKey(), entry.getValue());
338                                         errorList.add(errorMessage);
339                                     }
340                                         object.addJSONField(NodeRequest.ERRORS, errorList);
341                                         
342                                     } else {
343                                                 Object value = DocumentServerUtils.getValue(graph, attrib);
344                                             object.addJSONField(name, value);
345                                     }
346                                 } catch (Throwable t) {
347                                     List<String> errorList = object.getJSONField(NodeRequest.ERRORS);
348                                     if(errorList == null)
349                                         errorList = new ArrayList<String>();
350                                     
351                             String errorMessage = NodeRequestUtils.formatErrorMessage(name, t);
352                             
353                                     errorList.add(errorMessage);
354                                     object.addJSONField(NodeRequest.ERRORS, errorList);
355                                 }
356
357                         }
358
359                         return object;
360                         
361                 }
362                 
363         }
364
365         public static Collection<Variable> getDynamicAttributes(ReadGraph graph, final DocumentationResource DOC, Variable variable) throws DatabaseException {
366         Pair<JSONObject, Collection<Variable>> attribs = graph.syncRequest(new AttributesRequest(variable));
367         return attribs.second;
368         }
369         
370         public static Variable getPossibleDocumentRootVariable(ReadGraph graph, Variable documentPart) throws DatabaseException {
371                 if(documentPart instanceof RootVariable) return documentPart;
372                 Variable parent = documentPart.getParent(graph);
373                 if(parent == null) return null;
374                 return getPossibleDocumentRootVariable(graph, parent);
375         }
376
377 }