1 package org.simantics.structural.synchronization.base;
3 import gnu.trove.map.hash.THashMap;
4 import gnu.trove.procedure.TObjectObjectProcedure;
6 import java.util.ArrayList;
7 import java.util.Collections;
9 import org.simantics.databoard.util.URIStringUtils;
10 import org.simantics.structural.synchronization.protocol.SynchronizationEventHandler;
11 import org.simantics.structural.synchronization.utils.ComponentBase;
12 import org.simantics.structural.synchronization.utils.Solver;
13 import org.slf4j.Logger;
15 abstract public class ReferenceResolverBase<T extends ComponentBase<T>> {
17 protected SynchronizationEventHandler eventHandler;
18 protected Solver solver;
19 protected THashMap<T, ArrayList<PendingResolve<T>>> pendingResolves = new THashMap<T, ArrayList<PendingResolve<T>>>();
21 protected static class PendingResolve<T> {
22 public final T component;
23 public final String connectionPoint;
24 public final ModuleCallback moduleCallback;
26 public PendingResolve(T component, String connectionPoint,
27 ModuleCallback moduleCallback) {
28 this.component = component;
29 this.connectionPoint = connectionPoint;
30 this.moduleCallback = moduleCallback;
34 public String toString() {
35 return connectionPoint + "->" + moduleCallback;
39 public ReferenceResolverBase(Solver solver) {
43 public void setEventHandler(SynchronizationEventHandler eventHandler) {
44 this.eventHandler = eventHandler;
48 * Marks that the component might be updated in this synchronization and
49 * therefore it may not be yet used for resolving references.
51 public void markPending(T component) {
52 //System.out.println("markPending: " + fullPathOfComponent(component));
53 pendingResolves.put(component, new ArrayList<PendingResolve<T>>(2));
57 * Marks that the component is not modified anymore in this synchornization.
58 * This information is local, some children of the component may be marked
61 public void unmarkPending(T component) {
62 //System.out.println("unmarkPending: " + fullPathOfComponent(component));
63 ArrayList<PendingResolve<T>> resolves = pendingResolves.remove(component);
65 for(PendingResolve<T> resolve : resolves) {
66 resolveReference(resolve.component,
67 resolve.connectionPoint,
68 resolve.moduleCallback);
73 * Tries to resolve the given relative reference and then calls the ModuleCallback.
75 public void resolveReference(T component, String connectionPoint, ModuleCallback moduleCallback) {
78 char c = connectionPoint.charAt(pos++);
81 component = component.getParent();
86 c = connectionPoint.charAt(endPos);
87 if(c == '/' || c == '#')
91 String segment = URIStringUtils.unescape(connectionPoint.substring(pos, endPos));
93 component = component.getChild(segment);
94 if(component == null) {
95 String message = "Couldn't resolve " + connectionPoint +
96 ", because child " + segment + " does not exist.";
97 if(eventHandler == null)
98 getLogger().warn(message);
100 eventHandler.reportProblem(message);
103 ArrayList<PendingResolve<T>> pendingList = pendingResolves.get(component);
104 if(pendingList != null) {
105 pendingList.add(new PendingResolve<T>(component, connectionPoint.substring(pos), moduleCallback));
110 String segment = connectionPoint.substring(pos);
111 moduleCallback.execute(resolveConnectionPoint(component.componentId, segment));
117 abstract public int resolveConnectionPoint(int moduleId, String connectionPoint);
119 private static void fullPathOfComponent(StringBuilder b, ComponentBase<?> component) {
120 if(component != null) {
121 fullPathOfComponent(b, component.getParent());
122 b.append("/").append(component.solverComponentName);
126 private static String fullPathOfComponent(ComponentBase<?> component) {
127 StringBuilder b = new StringBuilder();
128 fullPathOfComponent(b, component);
132 public void printPending() {
133 if(!pendingResolves.isEmpty()) {
134 final ArrayList<String> pending = new ArrayList<String>();
135 pendingResolves.forEachEntry(new TObjectObjectProcedure<T, ArrayList<PendingResolve<T>>>() {
137 public boolean execute(T a, ArrayList<PendingResolve<T>> b) {
139 // System.out.println(" " + a.solverComponentName + " (" + a.uid + ", " + a.parent.solverComponentName + ") " + b.size());
140 pending.add(fullPathOfComponent(a) + " " + b);
144 Collections.sort(pending);
145 getLogger().info("Still pending:");
146 for(String p : pending)
147 getLogger().info(" " + p);
151 public void resolvePendingSelfReferences() {
152 // Can be customized in subclasses
155 public abstract Logger getLogger();