]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/base/ReferenceResolverBase.java
Sync git svn branch with SVN repository r33366.
[simantics/platform.git] / bundles / org.simantics.structural.synchronization.client / src / org / simantics / structural / synchronization / base / ReferenceResolverBase.java
1 package org.simantics.structural.synchronization.base;\r
2 \r
3 import gnu.trove.map.hash.THashMap;\r
4 import gnu.trove.procedure.TObjectObjectProcedure;\r
5 \r
6 import java.util.ArrayList;\r
7 import java.util.Collections;\r
8 \r
9 import org.simantics.databoard.util.URIStringUtils;\r
10 import org.simantics.structural.synchronization.protocol.SynchronizationEventHandler;\r
11 \r
12 abstract public class ReferenceResolverBase<T extends ComponentBase<T>> {\r
13         \r
14     protected SynchronizationEventHandler eventHandler;\r
15     protected Solver solver;\r
16     protected THashMap<T, ArrayList<PendingResolve<T>>> pendingResolves = new THashMap<T, ArrayList<PendingResolve<T>>>();\r
17 \r
18     protected static class PendingResolve<T> {\r
19         public final T component;\r
20         public final String connectionPoint;\r
21         public final ModuleCallback moduleCallback;\r
22         \r
23         public PendingResolve(T component, String connectionPoint,\r
24                 ModuleCallback moduleCallback) {\r
25             this.component = component;\r
26             this.connectionPoint = connectionPoint;\r
27             this.moduleCallback = moduleCallback;\r
28         }\r
29         \r
30         @Override\r
31         public String toString() {\r
32             return connectionPoint + "->" + moduleCallback;\r
33         }\r
34     }\r
35     \r
36     public ReferenceResolverBase(Solver solver) {\r
37         this.solver = solver;\r
38     }\r
39 \r
40     public void setEventHandler(SynchronizationEventHandler eventHandler) {\r
41         this.eventHandler = eventHandler;\r
42     }\r
43     \r
44     /**\r
45      * Marks that the component might be updated in this synchronization and\r
46      * therefore it may not be yet used for resolving references.\r
47      */\r
48     public void markPending(T component) {\r
49         //System.out.println("markPending: " + fullPathOfComponent(component));\r
50         pendingResolves.put(component, new ArrayList<PendingResolve<T>>(2));\r
51     }\r
52 \r
53     /**\r
54      * Marks that the component is not modified anymore in this synchornization.\r
55      * This information is local, some children of the component may be marked\r
56      * pending.\r
57      */\r
58     public void unmarkPending(T component) {\r
59         //System.out.println("unmarkPending: " + fullPathOfComponent(component));\r
60         ArrayList<PendingResolve<T>> resolves = pendingResolves.remove(component);\r
61         if(resolves != null)\r
62             for(PendingResolve<T> resolve : resolves) {\r
63                 resolveReference(resolve.component,\r
64                         resolve.connectionPoint,\r
65                         resolve.moduleCallback);\r
66             }\r
67     }\r
68 \r
69     /**\r
70      * Tries to resolve the given relative reference and then calls the ModuleCallback.\r
71      */\r
72     public void resolveReference(T component, String connectionPoint, ModuleCallback moduleCallback) {\r
73         int pos = 0;\r
74         while(true) {\r
75             char c = connectionPoint.charAt(pos++);\r
76             switch(c) {\r
77             case '.':\r
78                 component = component.getParent();\r
79                 break;\r
80             case '/': {\r
81                 int endPos = pos;\r
82                 while(true) {\r
83                     c = connectionPoint.charAt(endPos);\r
84                     if(c == '/' || c == '#')\r
85                         break;\r
86                     ++endPos;\r
87                 }\r
88                 String segment = URIStringUtils.unescape(connectionPoint.substring(pos, endPos));\r
89                 pos = endPos;\r
90                 component = component.getChild(segment);\r
91                 if(component == null) {\r
92                     String message = "Couldn't resolve " + connectionPoint +\r
93                             ", because child " + segment + " does not exist.";\r
94                     if(eventHandler == null)\r
95                         System.err.println(message);\r
96                     else\r
97                         eventHandler.reportProblem(message);\r
98                     return;\r
99                 }\r
100                 ArrayList<PendingResolve<T>> pendingList = pendingResolves.get(component);\r
101                 if(pendingList != null) {\r
102                     pendingList.add(new PendingResolve<T>(component, connectionPoint.substring(pos), moduleCallback));\r
103                     return;\r
104                 }\r
105             } break;\r
106             case '#': {\r
107                 String segment = connectionPoint.substring(pos);\r
108                 moduleCallback.execute(resolveConnectionPoint(component.componentId, segment));\r
109             } return;\r
110             }\r
111         }\r
112     }\r
113 \r
114     abstract public int resolveConnectionPoint(int moduleId, String connectionPoint);\r
115 \r
116     private static void fullPathOfComponent(StringBuilder b, ComponentBase<?> component) {\r
117         if(component != null) {\r
118             fullPathOfComponent(b, component.parent);\r
119             b.append("/").append(component.solverComponentName);\r
120         }\r
121     }\r
122     \r
123     private static String fullPathOfComponent(ComponentBase<?> component) {\r
124         StringBuilder b = new StringBuilder();\r
125         fullPathOfComponent(b, component);\r
126         return b.toString();\r
127     }\r
128     \r
129     public void printPending() {\r
130         if(!pendingResolves.isEmpty()) {\r
131             final ArrayList<String> pending = new ArrayList<String>();\r
132             pendingResolves.forEachEntry(new TObjectObjectProcedure<T, ArrayList<PendingResolve<T>>>() {\r
133                 @Override\r
134                 public boolean execute(T a, ArrayList<PendingResolve<T>> b) {\r
135                     //if(!b.isEmpty())\r
136                     //    System.out.println("    "  + a.solverComponentName + " (" + a.uid + ", " + a.parent.solverComponentName + ") " + b.size());\r
137                     pending.add(fullPathOfComponent(a) + " " + b);\r
138                     return true;\r
139                 }\r
140             });\r
141             Collections.sort(pending);\r
142             System.out.println("Still pending:");\r
143             for(String p : pending)\r
144                 System.out.println("    " + p);\r
145         }\r
146     }\r
147 \r
148     public void resolvePendingSelfReferences() {\r
149         // Can be customized in subclasses\r
150     }\r
151 \r
152 }\r