]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.document.server/src/org/simantics/document/server/DocumentServerUtils.java
Document performance optimizations
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / DocumentServerUtils.java
index 518881b5a1eb74309aa4f234bb479de4a8c69582..73c510317314e6937c4688ce5407c7146dd73081 100644 (file)
-package org.simantics.document.server;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Set;\r
-import java.util.SortedMap;\r
-import java.util.TreeMap;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.request.UnaryRead;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.request.VariableRead;\r
-import org.simantics.db.layer0.variable.ProxyChildVariable;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.document.base.ontology.DocumentationResource;\r
-import org.simantics.document.server.Functions.RootVariable;\r
-import org.simantics.structural2.variables.Connection;\r
-import org.simantics.structural2.variables.VariableConnectionPointDescriptor;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.strings.AlphanumComparator;\r
-\r
-public class DocumentServerUtils {\r
-\r
-    public static Collection<Variable> getChildren(ReadGraph graph, Variable variable) throws DatabaseException {\r
-\r
-       DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-       \r
-               ArrayList<Variable> result = new ArrayList<Variable>();\r
-               for(Variable property : variable.getProperties(graph)) {\r
-                       Collection<String> classifications = property.getPossiblePropertyValue(graph, Variables.CLASSIFICATIONS);\r
-                       if(classifications != null) {\r
-                               if(classifications.contains(DocumentationResource.URIs.Document_ChildRelation)) {\r
-                                       Connection conn = property.getValue(graph);\r
-                                       Variable childConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, property, conn);\r
-                                       if(childConnectionPoint != null) {\r
-                                               result.add(childConnectionPoint.getParent(graph));\r
-                                       }\r
-                               } else if (DOC.Relations_partN.equals(property.getPossiblePredicateResource(graph))) {\r
-                                       Connection conn = property.getValue(graph);\r
-                                       for (Variable childConnectionPoint : DocumentServerUtils.getOtherConnectionPoints(graph, property, conn)) {\r
-                                               result.add(childConnectionPoint.getParent(graph));\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return result;\r
-\r
-       }\r
-    \r
-       public static String findManualOrdinal(ReadGraph graph, Variable v) throws DatabaseException {\r
-               DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-               Integer j = null;\r
-               while (j == null && v != null) {\r
-                       j = v.getPossiblePropertyValue(graph, DOC.Components_Component_manualOrdinal);\r
-                       v = v.getParent(graph);\r
-               }\r
-               if (j != null) {\r
-                       return Integer.toString(j);\r
-               } else {\r
-                       return null;\r
-               }\r
-       }\r
-    \r
-    public static Collection<Variable> getChildrenInOrdinalOrder(ReadGraph graph, Variable variable) throws DatabaseException {\r
-       DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-       \r
-               SortedMap<String, Variable> childMap = new TreeMap<String, Variable>(AlphanumComparator.COMPARATOR);\r
-               \r
-               for(Variable property : variable.getProperties(graph)) {\r
-                       Collection<String> classifications = property.getPossiblePropertyValue(graph, Variables.CLASSIFICATIONS);\r
-                       if(classifications != null) {\r
-                               if(classifications.contains(DocumentationResource.URIs.Document_ChildRelation)) {\r
-                                       Resource cp = property.getPossiblePredicateResource(graph);\r
-                                       String i = graph.getRelatedValue(cp, DOC.Document_ChildRelation_ordinal, Bindings.STRING);\r
-                                       \r
-                                       Connection conn = property.getValue(graph);\r
-                                       Variable childConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, property, conn);\r
-                                       if(childConnectionPoint != null) {\r
-                                               childMap.put(i, childConnectionPoint.getParent(graph));\r
-                                       }\r
-                               } else if (DOC.Relations_partN.equals(property.getPossiblePredicateResource(graph))) {\r
-                                       Connection conn = property.getValue(graph);\r
-\r
-                                       for (Variable childConnectionPoint : DocumentServerUtils.getOtherConnectionPoints(graph, property, conn)) {\r
-                                               Variable child = childConnectionPoint.getParent(graph);\r
-                                               String i = findManualOrdinal(graph, child);\r
-                                               if (i == null) {\r
-                                                       i = "0";\r
-                                               }\r
-                                               childMap.put(i, child);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return childMap.values();\r
-\r
-       }    \r
-\r
-       public static Collection<Variable> collectNodes(ReadGraph graph, Variable variable, Collection<Variable> nodes) throws DatabaseException {\r
-\r
-               DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-\r
-               Resource type = variable.getPossibleType(graph);\r
-               if(type == null) return nodes;\r
-               \r
-               if(!graph.isInheritedFrom(type, DOC.Components_Component)) return nodes;\r
-\r
-               Boolean enabled = variable.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);\r
-               if(enabled != null && !enabled) return nodes;\r
-\r
-               if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {\r
-                       nodes.add(variable);\r
-               } else {\r
-                       for(Variable child : variable.getChildren(graph)) {\r
-                               collectNodes(graph, child, nodes);\r
-                       }\r
-               }\r
-\r
-               return nodes;\r
-\r
-       }\r
-\r
-       public static Variable getPossibleOtherConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {\r
-\r
-               Collection<VariableConnectionPointDescriptor> descs = conn.getConnectionPointDescriptors(graph, null);\r
-               if(descs.size() != 2) return null;\r
-\r
-               for(VariableConnectionPointDescriptor desc : descs) {\r
-                       if(desc.isFlattenedFrom(graph, connectionPoint)) continue;\r
-                       return desc.getVariable(graph);\r
-               }\r
-               \r
-               return null;\r
-\r
-       }\r
-       \r
-       public static Collection<Variable> getOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {\r
-\r
-               ArrayList<Variable> connectionPoints = new ArrayList<Variable>();\r
-               \r
-               Collection<VariableConnectionPointDescriptor> descs = conn.getConnectionPointDescriptors(graph, null);\r
-\r
-               for(VariableConnectionPointDescriptor desc : descs) {\r
-                       if(desc.isFlattenedFrom(graph, connectionPoint)) continue;\r
-                       connectionPoints.add(desc.getVariable(graph));\r
-               }\r
-               \r
-               return connectionPoints;\r
-\r
-       }\r
-\r
-       public static Variable getPossibleCommandTriggerConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {\r
-\r
-               Collection<Variable> cpts = conn.getConnectionPoints(graph, null);\r
-\r
-               Variable result = null;\r
-               \r
-               for(Variable cpt : cpts) {\r
-                       Set<String> classifications = cpt.getClassifications(graph);\r
-                       if(classifications.contains(DocumentationResource.URIs.Relations_commandExecutorRelation)) {\r
-                               if(result != null) throw new DatabaseException("Multiple executor connection points in command connection");\r
-                               result = cpt;\r
-                       }\r
-               }\r
-               \r
-               return result;\r
-\r
-       }\r
-\r
-       public static Collection<Variable> getPossibleOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {\r
-\r
-           Collection<Variable> cpts = conn.getConnectionPoints(graph, null);\r
-           if(cpts.size() < 2) \r
-               return Collections.emptyList();\r
-\r
-           ArrayList<Variable> result = new ArrayList<Variable>();\r
-           for(Variable cpt : cpts) {\r
-               if(!cpt.equals(connectionPoint)) \r
-                   result.add(cpt);\r
-           }\r
-           return result;\r
-       }\r
-\r
-       public static String getId(ReadGraph graph, Variable node) throws DatabaseException {\r
-\r
-               if(node == null) return "root";\r
-               else {\r
-                       String uri = node.getURI(graph); \r
-                       int l = uri.lastIndexOf(ProxyChildVariable.CONTEXT_END);\r
-                       return uri.substring(l+4);\r
-               }\r
-\r
-       }\r
-\r
-       public static class DocumentValue extends VariableRead<Object> {\r
-\r
-               public DocumentValue(Variable variable) {\r
-                       super(variable);\r
-               }\r
-\r
-               @Override\r
-               public Object perform(ReadGraph graph) throws DatabaseException {\r
-                       return variable.getValue(graph);\r
-               }\r
-               \r
-               @Override\r
-               public String toString() {\r
-                       return "DocumentValue[" + variable + "]";\r
-               }\r
-               \r
-       }\r
-       \r
-       public static Object getValue(ReadGraph graph, Variable attrib) throws DatabaseException {\r
-               return graph.syncRequest(new DocumentValue(attrib));\r
-       }\r
-\r
-       public static Variable getParentConnectionPoint(ReadGraph graph, Variable component) throws DatabaseException {\r
-\r
-               Variable connectionPoint = component.getPossibleProperty(graph, "parent");\r
-               if(connectionPoint == null) {\r
-                       DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-                       Collection<Variable> cps = component.getProperties(graph, DOC.Relations_parentRelation);\r
-                       if(cps.size() == 1) {\r
-                               connectionPoint = cps.iterator().next();\r
-                       } else {\r
-                               return null;\r
-                       }\r
-               }\r
-               \r
-               Connection conn = connectionPoint.getValue(graph);\r
-               Variable otherCp = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, connectionPoint, conn);\r
-               if (otherCp != null) {\r
-                       return otherCp;\r
-               } else {\r
-                       Variable parentCp = graph.sync(new UnaryRead<Connection, Variable>(conn) {\r
-                   @Override\r
-                   public Variable perform(ReadGraph graph) throws DatabaseException {\r
-                       DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-                       Collection<VariableConnectionPointDescriptor> descs = parameter.getConnectionPointDescriptors(graph, null);\r
-\r
-                               for(VariableConnectionPointDescriptor desc : descs) {\r
-                                       if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {\r
-                                               return desc.getVariable(graph);\r
-                                       }\r
-                               }\r
-                               return null;\r
-                   }\r
-               });\r
-                       if (parentCp != null) {\r
-                               return parentCp;\r
-                       }\r
-               }\r
-               return null;\r
-\r
-       }\r
-       \r
-       /* Children */\r
-       public static Collection<Variable> getChildConnections(ReadGraph graph, Variable variable) throws DatabaseException {\r
-               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_ChildRelation);\r
-       }\r
-\r
-       /* Command sequence */\r
-       public static Collection<Variable> getTriggerCommands(ReadGraph graph, Variable variable) throws DatabaseException {\r
-               ArrayList<Variable> result = new ArrayList<Variable>();\r
-               DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-               for(Variable var : variable.getProperties(graph, DOC.Document_CommandRelation)) {\r
-            if(DOC.Relations_broadcasted.equals(var.getPredicateResource(graph))) continue;\r
-            result.add(var);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       public static Collection<Variable> getCommands(ReadGraph graph, Variable variable) throws DatabaseException {\r
-               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_CommandRelation);\r
-       }\r
-\r
-       /* Data definition */\r
-       public static Collection<Variable> getDataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException {\r
-               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_DataDefinitionRelation);\r
-       }\r
-\r
-       /* Data relation */\r
-       public static Collection<Variable> getDataRelations(ReadGraph graph, Variable variable) throws DatabaseException {\r
-               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_DataRelation);\r
-       }\r
-\r
-       /* Attributes */\r
-       public static Collection<Variable> getAttributes(ReadGraph graph, DocumentationResource DOC, Variable variable) throws DatabaseException {\r
-               return variable.getProperties(graph, DOC.Document_AttributeRelation);\r
-       }\r
-       \r
-       static class AttributesRequest extends VariableRead<Pair<Collection<Variable>, Collection<Variable>>> {\r
-\r
-               public AttributesRequest(Variable variable) {\r
-                       super(variable);\r
-               }\r
-\r
-               @Override\r
-               public Pair<Collection<Variable>,Collection<Variable>> perform(ReadGraph graph) throws DatabaseException {\r
-               ArrayList<Variable> statics = new ArrayList<Variable>();\r
-               ArrayList<Variable> dynamics = new ArrayList<Variable>();\r
-               DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
-               for(Variable property : getAttributes(graph, DOC, variable)) {\r
-                       Boolean defaultProperty = property.getPossiblePropertyValue(graph, "default");\r
-                       if(defaultProperty != null && defaultProperty) {\r
-//                             System.err.println("" + property.getURI(graph) + " is default");\r
-                               continue;\r
-                       } \r
-//                     else {\r
-//                             System.err.println("" + property.getURI(graph) + " is not default");\r
-//                     }\r
-                       Boolean dynamicProperty = property.getPossiblePropertyValue(graph, DOC.Document_AttributeRelation_dynamic);\r
-                       if(dynamicProperty != null && dynamicProperty) dynamics.add(property);\r
-                       else statics.add(property);\r
-               }\r
-               return new Pair<Collection<Variable>, Collection<Variable>>(statics, dynamics);\r
-               }\r
-               \r
-       }\r
-       \r
-    public static Collection<Variable> getStaticAttributes(ReadGraph graph, DocumentationResource DOC, Variable variable) throws DatabaseException {\r
-       Pair<Collection<Variable>, Collection<Variable>> attribs = graph.syncRequest(new AttributesRequest(variable));\r
-       return attribs.first;\r
-    }\r
-\r
-       public static Collection<Variable> getDynamicAttributes(ReadGraph graph, final DocumentationResource DOC, Variable variable) throws DatabaseException {\r
-       Pair<Collection<Variable>, Collection<Variable>> attribs = graph.syncRequest(new AttributesRequest(variable));\r
-       return attribs.second;\r
-       }\r
-       \r
-       public static Variable getPossibleDocumentRootVariable(ReadGraph graph, Variable documentPart) throws DatabaseException {\r
-               if(documentPart instanceof RootVariable) return documentPart;\r
-               Variable parent = documentPart.getParent(graph);\r
-               if(parent == null) return null;\r
-               return getPossibleDocumentRootVariable(graph, parent);\r
-       }\r
-\r
-}\r
+package org.simantics.document.server;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.UnaryRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.request.VariableRead;
+import org.simantics.db.layer0.variable.ProxyChildVariable;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.document.base.ontology.DocumentationResource;
+import org.simantics.document.server.request.NodeRequest;
+import org.simantics.document.server.request.NodeRequestUtils;
+import org.simantics.structural2.variables.Connection;
+import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
+import org.simantics.utils.strings.AlphanumComparator;
+
+public class DocumentServerUtils {
+
+    public static Collection<Variable> getChildren(ReadGraph graph, Variable variable) throws DatabaseException {
+
+       DocumentationResource DOC = DocumentationResource.getInstance(graph);
+       
+               ArrayList<Variable> result = new ArrayList<Variable>();
+               for(Variable property : variable.getProperties(graph)) {
+                       Collection<String> classifications = property.getPossiblePropertyValue(graph, Variables.CLASSIFICATIONS);
+                       if(classifications != null) {
+                               if(classifications.contains(DocumentationResource.URIs.Document_ChildRelation)) {
+                                       Connection conn = property.getValue(graph);
+                                       Variable childConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, property, conn);
+                                       if(childConnectionPoint != null) {
+                                               result.add(childConnectionPoint.getParent(graph));
+                                       }
+                               } else if (DOC.Relations_partN.equals(property.getPossiblePredicateResource(graph))) {
+                                       Connection conn = property.getValue(graph);
+                                       for (Variable childConnectionPoint : DocumentServerUtils.getOtherConnectionPoints(graph, property, conn)) {
+                                               result.add(childConnectionPoint.getParent(graph));
+                                       }
+                               }
+                       }
+               }
+               return result;
+
+       }
+    
+       public static String findManualOrdinal(ReadGraph graph, Variable v) throws DatabaseException {
+               DocumentationResource DOC = DocumentationResource.getInstance(graph);
+               Integer j = null;
+               while (j == null && v != null) {
+                       j = v.getPossiblePropertyValue(graph, DOC.Components_Component_manualOrdinal);
+                       v = v.getParent(graph);
+               }
+               if (j != null) {
+                       return Integer.toString(j);
+               } else {
+                       return null;
+               }
+       }
+    
+    public static Collection<Variable> getChildrenInOrdinalOrder(ReadGraph graph, Variable variable) throws DatabaseException {
+       DocumentationResource DOC = DocumentationResource.getInstance(graph);
+       
+               SortedMap<String, Variable> childMap = new TreeMap<String, Variable>(AlphanumComparator.COMPARATOR);
+               
+               for(Variable property : variable.getProperties(graph, DocumentationResource.URIs.Document_ChildRelation)) {
+                       Resource cp = property.getPossiblePredicateResource(graph);
+                       String i = graph.getRelatedValue(cp, DOC.Document_ChildRelation_ordinal, Bindings.STRING);
+                       Connection conn = property.getValue(graph);
+                       Variable childConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, property, conn);
+                       if(childConnectionPoint != null) {
+                               childMap.put(i, childConnectionPoint.getParent(graph));
+                       }
+               }
+               
+               Variable property = variable.getPossibleProperty(graph, "partN");
+               if(property != null) {
+                       Connection conn = property.getValue(graph);
+                       for (Variable childConnectionPoint : DocumentServerUtils.getOtherConnectionPoints(graph, property, conn)) {
+                               Variable child = childConnectionPoint.getParent(graph);
+                               String i = findManualOrdinal(graph, child);
+                               if (i == null) {
+                                       i = "0";
+                               }
+                               childMap.put(i, child);
+                       }
+               }
+
+               return childMap.values();
+
+       }    
+
+       public static Collection<Variable> collectNodes(ReadGraph graph, Variable variable, Collection<Variable> nodes) throws DatabaseException {
+
+               DocumentationResource DOC = DocumentationResource.getInstance(graph);
+
+               Resource type = variable.getPossibleType(graph);
+               if(type == null) return nodes;
+               
+               if(!graph.isInheritedFrom(type, DOC.Components_Component)) return nodes;
+
+               Boolean enabled = variable.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);
+               if(enabled != null && !enabled) return nodes;
+
+               if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {
+                       nodes.add(variable);
+               } else {
+                       for(Variable child : variable.getChildren(graph)) {
+                               collectNodes(graph, child, nodes);
+                       }
+               }
+
+               return nodes;
+
+       }
+
+       public static Variable getPossibleOtherConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
+
+               Collection<VariableConnectionPointDescriptor> descs = conn.getConnection2().getConnectionPointDescriptors(graph, connectionPoint.getParent(graph), null);
+               if(descs.size() != 2) return null;
+
+               for(VariableConnectionPointDescriptor desc : descs) {
+                       if(desc.isFlattenedFrom(graph, connectionPoint)) continue;
+                       return desc.getVariable(graph);
+               }
+               
+               return null;
+
+       }
+
+       public static Variable getPossibleChildConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
+
+               Collection<VariableConnectionPointDescriptor> descs = conn.getConnection2().getConnectionPointDescriptors(graph, connectionPoint.getParent(graph), null);
+               if(descs.size() != 2) return null;
+
+       DocumentationResource DOC = DocumentationResource.getInstance(graph);
+               
+               for(VariableConnectionPointDescriptor desc : descs) {
+                       Resource res = desc.getConnectionPointResource(graph);
+                       if(graph.isInstanceOf(res, DOC.Relations_parentRelation)) continue;
+                       //if(desc.isFlattenedFrom(graph, connectionPoint)) continue;
+                       return desc.getVariable(graph);
+               }
+               
+               return null;
+
+       }
+       
+       public static Collection<Variable> getOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
+
+               ArrayList<Variable> connectionPoints = new ArrayList<Variable>();
+               
+               Collection<VariableConnectionPointDescriptor> descs = conn.getConnectionPointDescriptors(graph, null);
+
+               for(VariableConnectionPointDescriptor desc : descs) {
+                       if(desc.isFlattenedFrom(graph, connectionPoint)) continue;
+                       connectionPoints.add(desc.getVariable(graph));
+               }
+               
+               return connectionPoints;
+
+       }
+
+       public static Variable getPossibleCommandTriggerConnectionPoint(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
+
+               Collection<Variable> cpts = conn.getConnection2().getConnectionPoints(graph, connectionPoint.getParent(graph), null);
+
+               Variable result = null;
+               
+               for(Variable cpt : cpts) {
+                       Set<String> classifications = cpt.getClassifications(graph);
+                       if(classifications.contains(DocumentationResource.URIs.Relations_commandExecutorRelation)) {
+                               if(result != null) throw new DatabaseException("Multiple executor connection points in command connection");
+                               result = cpt;
+                       }
+               }
+               
+               return result;
+
+       }
+
+       public static Collection<Variable> getPossibleOtherConnectionPoints(ReadGraph graph, Variable connectionPoint, Connection conn) throws DatabaseException {
+
+           Collection<Variable> cpts = conn.getConnection2().getConnectionPoints(graph, connectionPoint.getParent(graph), null);
+           if(cpts.size() < 2) 
+               return Collections.emptyList();
+
+           ArrayList<Variable> result = new ArrayList<Variable>();
+           for(Variable cpt : cpts) {
+               if(!cpt.equals(connectionPoint)) 
+                   result.add(cpt);
+           }
+           return result;
+       }
+
+       public static String getId(ReadGraph graph, Variable node) throws DatabaseException {
+
+        if(node == null) return "root";
+        else {
+            String name = node.getName(graph);
+            if(ProxyChildVariable.CONTEXT_END.equals(name)) return "";
+            else {
+                String parentId = getId(graph, node.getParent(graph));
+                if(parentId.isEmpty()) return name;
+                else return parentId + "/" + name; 
+            }
+            
+        }
+
+       }
+
+       public static Object getValue(ReadGraph graph, Variable attrib) throws DatabaseException {
+               return graph.syncRequest(new DocumentValue(attrib));
+       }
+
+       public static Variable getParentConnectionPoint(ReadGraph graph, Variable component) throws DatabaseException {
+
+               Variable connectionPoint = component.getPossibleProperty(graph, "parent");
+               if(connectionPoint == null) {
+                       DocumentationResource DOC = DocumentationResource.getInstance(graph);
+                       Collection<Variable> cps = component.getProperties(graph, DOC.Relations_parentRelation);
+                       if(cps.size() == 1) {
+                               connectionPoint = cps.iterator().next();
+                       } else {
+                               return null;
+                       }
+               }
+               
+               Connection conn = connectionPoint.getValue(graph);
+               Variable otherCp = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, connectionPoint, conn);
+               if (otherCp != null) {
+                       return otherCp;
+               } else {
+                       Variable parentCp = graph.sync(new UnaryRead<Connection, Variable>(conn) {
+                   @Override
+                   public Variable perform(ReadGraph graph) throws DatabaseException {
+                       DocumentationResource DOC = DocumentationResource.getInstance(graph);
+                       Collection<VariableConnectionPointDescriptor> descs = parameter.getConnectionPointDescriptors(graph, null);
+
+                               for(VariableConnectionPointDescriptor desc : descs) {
+                                       if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {
+                                               return desc.getVariable(graph);
+                                       }
+                               }
+                               return null;
+                   }
+               });
+                       if (parentCp != null) {
+                               return parentCp;
+                       }
+               }
+               return null;
+
+       }
+       
+       /* Children */
+       public static Collection<Variable> getChildConnections(ReadGraph graph, Variable variable) throws DatabaseException {
+               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_ChildRelation);
+       }
+
+       /* Command sequence */
+       public static Collection<Variable> getTriggerCommands(ReadGraph graph, Variable variable) throws DatabaseException {
+               ArrayList<Variable> result = new ArrayList<Variable>();
+               DocumentationResource DOC = DocumentationResource.getInstance(graph);
+               for(Variable var : variable.getProperties(graph, DOC.Document_CommandRelation)) {
+            if(DOC.Relations_broadcasted.equals(var.getPredicateResource(graph))) continue;
+            result.add(var);
+               }
+               return result;
+       }
+
+       public static Collection<Variable> getCommands(ReadGraph graph, Variable variable) throws DatabaseException {
+               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_CommandRelation);
+       }
+
+       /* Data definition */
+       public static Collection<Variable> getDataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException {
+               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_DataDefinitionRelation);
+       }
+
+       /* Data relation */
+       public static Collection<Variable> getDataRelations(ReadGraph graph, Variable variable) throws DatabaseException {
+               return variable.getProperties(graph, DocumentationResource.getInstance(graph).Document_DataRelation);
+       }
+
+       /* Attributes */
+       public static Collection<Variable> getAttributes(ReadGraph graph, DocumentationResource DOC, Variable variable) throws DatabaseException {
+               return variable.getProperties(graph, DOC.Document_AttributeRelation);
+       }
+
+       public static class AttributesRequest extends VariableRead<JSONObject> {
+
+               public AttributesRequest(Variable variable) {
+                       super(variable);
+               }
+
+               @Override
+               public JSONObject perform(ReadGraph graph) throws DatabaseException {
+                       DocumentProperties properties = variable.getPropertyValue(graph, "primitiveProperties");
+                       return computeStatic(graph, variable, properties);
+               }
+
+               JSONObject computeStatic(ReadGraph graph, Variable variable, DocumentProperties statics) throws DatabaseException {
+
+                       JSONObject base = graph.syncRequest(new org.simantics.document.server.request.DefaultFields(variable));
+                       JSONObject object = base.clone();
+
+                       for(String name : statics.getKeys(graph, variable)) {
+                               try {
+                                       if (name.equals(NodeRequest.PROPERTY_VALUE_EXCEPTIONS)) {
+                                               @SuppressWarnings("unchecked")
+                                               Map<String, Exception> exceptions = (Map<String, Exception>)statics.getValue(graph, variable, name);
+
+                                               List<String> errorList = object.getJSONField(NodeRequest.ERRORS);
+                                               if(errorList == null)
+                                                       errorList = new ArrayList<>();
+
+                                               for (Map.Entry<String, Exception> entry : exceptions.entrySet()) {
+                                                       String errorMessage = NodeRequestUtils.formatErrorMessage(entry.getKey(), entry.getValue());
+                                                       errorList.add(errorMessage);
+                                               }
+                                               object.addJSONField(NodeRequest.ERRORS, errorList);
+                                       } else {
+                                               object.addJSONField(name, statics.getValue(graph, variable, name));
+                                       }
+                               } catch (Throwable t) {
+                                       List<String> errorList = object.getJSONField(NodeRequest.ERRORS);
+                                       if(errorList == null)
+                                               errorList = new ArrayList<>(1);
+
+                                       String errorMessage = NodeRequestUtils.formatErrorMessage(name, t);
+                                       errorList.add(errorMessage);
+                                       object.addJSONField(NodeRequest.ERRORS, errorList);
+                               }
+
+                       }
+
+                       return object;
+
+               }
+
+       }
+
+       public static Collection<Variable> getDynamicAttributes(ReadGraph graph, final DocumentationResource DOC, Variable variable) throws DatabaseException {
+               return Collections.emptyList();
+       }
+
+       public static Variable getPossibleDocumentRootVariable(ReadGraph graph, Variable documentPart) throws DatabaseException {
+               if(ProxyChildVariable.CONTEXT_END.equals(documentPart.getName(graph))) return documentPart;
+               Variable parent = documentPart.getParent(graph);
+               if(parent == null) return null;
+               return getPossibleDocumentRootVariable(graph, parent);
+       }
+
+}