1 package org.simantics.structural.synchronization.base;
\r
3 import gnu.trove.map.hash.THashMap;
\r
4 import gnu.trove.procedure.TObjectObjectProcedure;
\r
6 import java.util.ArrayList;
\r
7 import java.util.Collections;
\r
9 import org.simantics.databoard.util.URIStringUtils;
\r
10 import org.simantics.structural.synchronization.protocol.SynchronizationEventHandler;
\r
12 abstract public class ReferenceResolverBase<T extends ComponentBase<T>> {
\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
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
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
31 public String toString() {
\r
32 return connectionPoint + "->" + moduleCallback;
\r
36 public ReferenceResolverBase(Solver solver) {
\r
37 this.solver = solver;
\r
40 public void setEventHandler(SynchronizationEventHandler eventHandler) {
\r
41 this.eventHandler = eventHandler;
\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
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
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
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
70 * Tries to resolve the given relative reference and then calls the ModuleCallback.
\r
72 public void resolveReference(T component, String connectionPoint, ModuleCallback moduleCallback) {
\r
75 char c = connectionPoint.charAt(pos++);
\r
78 component = component.getParent();
\r
83 c = connectionPoint.charAt(endPos);
\r
84 if(c == '/' || c == '#')
\r
88 String segment = URIStringUtils.unescape(connectionPoint.substring(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
97 eventHandler.reportProblem(message);
\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
107 String segment = connectionPoint.substring(pos);
\r
108 moduleCallback.execute(resolveConnectionPoint(component.componentId, segment));
\r
114 abstract public int resolveConnectionPoint(int moduleId, String connectionPoint);
\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
123 private static String fullPathOfComponent(ComponentBase<?> component) {
\r
124 StringBuilder b = new StringBuilder();
\r
125 fullPathOfComponent(b, component);
\r
126 return b.toString();
\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
134 public boolean execute(T a, ArrayList<PendingResolve<T>> b) {
\r
136 // System.out.println(" " + a.solverComponentName + " (" + a.uid + ", " + a.parent.solverComponentName + ") " + b.size());
\r
137 pending.add(fullPathOfComponent(a) + " " + b);
\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
148 public void resolvePendingSelfReferences() {
\r
149 // Can be customized in subclasses
\r