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.slf4j.Logger;
13 abstract public class ReferenceResolverBase<T extends ComponentBase<T>> {
15 protected SynchronizationEventHandler eventHandler;
16 protected Solver solver;
17 protected THashMap<T, ArrayList<PendingResolve<T>>> pendingResolves = new THashMap<T, ArrayList<PendingResolve<T>>>();
19 protected static class PendingResolve<T> {
20 public final T component;
21 public final String connectionPoint;
22 public final ModuleCallback moduleCallback;
24 public PendingResolve(T component, String connectionPoint,
25 ModuleCallback moduleCallback) {
26 this.component = component;
27 this.connectionPoint = connectionPoint;
28 this.moduleCallback = moduleCallback;
32 public String toString() {
33 return connectionPoint + "->" + moduleCallback;
37 public ReferenceResolverBase(Solver solver) {
41 public void setEventHandler(SynchronizationEventHandler eventHandler) {
42 this.eventHandler = eventHandler;
46 * Marks that the component might be updated in this synchronization and
47 * therefore it may not be yet used for resolving references.
49 public void markPending(T component) {
50 //System.out.println("markPending: " + fullPathOfComponent(component));
51 pendingResolves.put(component, new ArrayList<PendingResolve<T>>(2));
55 * Marks that the component is not modified anymore in this synchornization.
56 * This information is local, some children of the component may be marked
59 public void unmarkPending(T component) {
60 //System.out.println("unmarkPending: " + fullPathOfComponent(component));
61 ArrayList<PendingResolve<T>> resolves = pendingResolves.remove(component);
63 for(PendingResolve<T> resolve : resolves) {
64 resolveReference(resolve.component,
65 resolve.connectionPoint,
66 resolve.moduleCallback);
71 * Tries to resolve the given relative reference and then calls the ModuleCallback.
73 public void resolveReference(T component, String connectionPoint, ModuleCallback moduleCallback) {
76 char c = connectionPoint.charAt(pos++);
79 component = component.getParent();
84 c = connectionPoint.charAt(endPos);
85 if(c == '/' || c == '#')
89 String segment = URIStringUtils.unescape(connectionPoint.substring(pos, endPos));
91 component = component.getChild(segment);
92 if(component == null) {
93 String message = "Couldn't resolve " + connectionPoint +
94 ", because child " + segment + " does not exist.";
95 if(eventHandler == null)
96 getLogger().warn(message);
98 eventHandler.reportProblem(message);
101 ArrayList<PendingResolve<T>> pendingList = pendingResolves.get(component);
102 if(pendingList != null) {
103 pendingList.add(new PendingResolve<T>(component, connectionPoint.substring(pos), moduleCallback));
108 String segment = connectionPoint.substring(pos);
109 moduleCallback.execute(resolveConnectionPoint(component.componentId, segment));
115 abstract public int resolveConnectionPoint(int moduleId, String connectionPoint);
117 private static void fullPathOfComponent(StringBuilder b, ComponentBase<?> component) {
118 if(component != null) {
119 fullPathOfComponent(b, component.parent);
120 b.append("/").append(component.solverComponentName);
124 private static String fullPathOfComponent(ComponentBase<?> component) {
125 StringBuilder b = new StringBuilder();
126 fullPathOfComponent(b, component);
130 public void printPending() {
131 if(!pendingResolves.isEmpty()) {
132 final ArrayList<String> pending = new ArrayList<String>();
133 pendingResolves.forEachEntry(new TObjectObjectProcedure<T, ArrayList<PendingResolve<T>>>() {
135 public boolean execute(T a, ArrayList<PendingResolve<T>> b) {
137 // System.out.println(" " + a.solverComponentName + " (" + a.uid + ", " + a.parent.solverComponentName + ") " + b.size());
138 pending.add(fullPathOfComponent(a) + " " + b);
142 Collections.sort(pending);
143 getLogger().info("Still pending:");
144 for(String p : pending)
145 getLogger().info(" " + p);
149 public void resolvePendingSelfReferences() {
150 // Can be customized in subclasses
153 public abstract Logger getLogger();