]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/base/ReferenceResolverBase.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.structural.synchronization.client / src / org / simantics / structural / synchronization / base / ReferenceResolverBase.java
diff --git a/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/base/ReferenceResolverBase.java b/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/base/ReferenceResolverBase.java
new file mode 100644 (file)
index 0000000..19f4538
--- /dev/null
@@ -0,0 +1,152 @@
+package org.simantics.structural.synchronization.base;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.procedure.TObjectObjectProcedure;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+\r
+import org.simantics.databoard.util.URIStringUtils;\r
+import org.simantics.structural.synchronization.protocol.SynchronizationEventHandler;\r
+\r
+abstract public class ReferenceResolverBase<T extends ComponentBase<T>> {\r
+       \r
+    protected SynchronizationEventHandler eventHandler;\r
+    protected Solver solver;\r
+    protected THashMap<T, ArrayList<PendingResolve<T>>> pendingResolves = new THashMap<T, ArrayList<PendingResolve<T>>>();\r
+\r
+    protected static class PendingResolve<T> {\r
+        public final T component;\r
+        public final String connectionPoint;\r
+        public final ModuleCallback moduleCallback;\r
+        \r
+        public PendingResolve(T component, String connectionPoint,\r
+                ModuleCallback moduleCallback) {\r
+            this.component = component;\r
+            this.connectionPoint = connectionPoint;\r
+            this.moduleCallback = moduleCallback;\r
+        }\r
+        \r
+        @Override\r
+        public String toString() {\r
+            return connectionPoint + "->" + moduleCallback;\r
+        }\r
+    }\r
+    \r
+    public ReferenceResolverBase(Solver solver) {\r
+        this.solver = solver;\r
+    }\r
+\r
+    public void setEventHandler(SynchronizationEventHandler eventHandler) {\r
+        this.eventHandler = eventHandler;\r
+    }\r
+    \r
+    /**\r
+     * Marks that the component might be updated in this synchronization and\r
+     * therefore it may not be yet used for resolving references.\r
+     */\r
+    public void markPending(T component) {\r
+        //System.out.println("markPending: " + fullPathOfComponent(component));\r
+        pendingResolves.put(component, new ArrayList<PendingResolve<T>>(2));\r
+    }\r
+\r
+    /**\r
+     * Marks that the component is not modified anymore in this synchornization.\r
+     * This information is local, some children of the component may be marked\r
+     * pending.\r
+     */\r
+    public void unmarkPending(T component) {\r
+        //System.out.println("unmarkPending: " + fullPathOfComponent(component));\r
+        ArrayList<PendingResolve<T>> resolves = pendingResolves.remove(component);\r
+        if(resolves != null)\r
+            for(PendingResolve<T> resolve : resolves) {\r
+                resolveReference(resolve.component,\r
+                        resolve.connectionPoint,\r
+                        resolve.moduleCallback);\r
+            }\r
+    }\r
+\r
+    /**\r
+     * Tries to resolve the given relative reference and then calls the ModuleCallback.\r
+     */\r
+    public void resolveReference(T component, String connectionPoint, ModuleCallback moduleCallback) {\r
+        int pos = 0;\r
+        while(true) {\r
+            char c = connectionPoint.charAt(pos++);\r
+            switch(c) {\r
+            case '.':\r
+                component = component.getParent();\r
+                break;\r
+            case '/': {\r
+                int endPos = pos;\r
+                while(true) {\r
+                    c = connectionPoint.charAt(endPos);\r
+                    if(c == '/' || c == '#')\r
+                        break;\r
+                    ++endPos;\r
+                }\r
+                String segment = URIStringUtils.unescape(connectionPoint.substring(pos, endPos));\r
+                pos = endPos;\r
+                component = component.getChild(segment);\r
+                if(component == null) {\r
+                    String message = "Couldn't resolve " + connectionPoint +\r
+                            ", because child " + segment + " does not exist.";\r
+                    if(eventHandler == null)\r
+                        System.err.println(message);\r
+                    else\r
+                        eventHandler.reportProblem(message);\r
+                    return;\r
+                }\r
+                ArrayList<PendingResolve<T>> pendingList = pendingResolves.get(component);\r
+                if(pendingList != null) {\r
+                    pendingList.add(new PendingResolve<T>(component, connectionPoint.substring(pos), moduleCallback));\r
+                    return;\r
+                }\r
+            } break;\r
+            case '#': {\r
+                String segment = connectionPoint.substring(pos);\r
+                moduleCallback.execute(resolveConnectionPoint(component.componentId, segment));\r
+            } return;\r
+            }\r
+        }\r
+    }\r
+\r
+    abstract public int resolveConnectionPoint(int moduleId, String connectionPoint);\r
+\r
+    private static void fullPathOfComponent(StringBuilder b, ComponentBase<?> component) {\r
+        if(component != null) {\r
+            fullPathOfComponent(b, component.parent);\r
+            b.append("/").append(component.solverComponentName);\r
+        }\r
+    }\r
+    \r
+    private static String fullPathOfComponent(ComponentBase<?> component) {\r
+        StringBuilder b = new StringBuilder();\r
+        fullPathOfComponent(b, component);\r
+        return b.toString();\r
+    }\r
+    \r
+    public void printPending() {\r
+        if(!pendingResolves.isEmpty()) {\r
+            final ArrayList<String> pending = new ArrayList<String>();\r
+            pendingResolves.forEachEntry(new TObjectObjectProcedure<T, ArrayList<PendingResolve<T>>>() {\r
+                @Override\r
+                public boolean execute(T a, ArrayList<PendingResolve<T>> b) {\r
+                    //if(!b.isEmpty())\r
+                    //    System.out.println("    "  + a.solverComponentName + " (" + a.uid + ", " + a.parent.solverComponentName + ") " + b.size());\r
+                    pending.add(fullPathOfComponent(a) + " " + b);\r
+                    return true;\r
+                }\r
+            });\r
+            Collections.sort(pending);\r
+            System.out.println("Still pending:");\r
+            for(String p : pending)\r
+                System.out.println("    " + p);\r
+        }\r
+    }\r
+\r
+    public void resolvePendingSelfReferences() {\r
+        // Can be customized in subclasses\r
+    }\r
+\r
+}\r