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