Index: java/main/src/main/java/com/framsticks/remote/RemoteInstance.java
===================================================================
--- java/main/src/main/java/com/framsticks/remote/RemoteInstance.java	(revision 90)
+++ java/main/src/main/java/com/framsticks/remote/RemoteInstance.java	(revision 96)
@@ -2,9 +2,12 @@
 
 import com.framsticks.communication.*;
+import com.framsticks.communication.queries.CallRequest;
 import com.framsticks.communication.queries.GetRequest;
 import com.framsticks.communication.queries.InfoRequest;
 import com.framsticks.communication.queries.SetRequest;
-import com.framsticks.communication.util.LoggingSubscriptionCallback;
+import com.framsticks.core.AbstractInstance;
+import com.framsticks.core.InstanceUtils;
 import com.framsticks.core.ListChange;
+import com.framsticks.core.Node;
 import com.framsticks.core.Path;
 import com.framsticks.params.*;
@@ -17,4 +20,5 @@
 import com.framsticks.util.*;
 import com.framsticks.util.dispatching.Dispatching;
+import com.framsticks.util.dispatching.ExceptionResultHandler;
 import com.framsticks.util.dispatching.Future;
 import com.framsticks.util.dispatching.Joinable;
@@ -24,6 +28,9 @@
 import com.framsticks.util.lang.Pair;
 import com.framsticks.util.dispatching.RunAt;
+import static com.framsticks.core.InstanceUtils.*;
 
 import java.util.*;
+
+import javax.annotation.Nonnull;
 
 import org.apache.log4j.Logger;
@@ -33,9 +40,8 @@
  */
 @FramsClassAnnotation
-public class RemoteInstance extends Instance implements JoinableParent {
+public class RemoteInstance extends AbstractInstance implements JoinableParent {
 
 	private final static Logger log = Logger.getLogger(RemoteInstance.class.getName());
 
-	protected Path simulator;
 	protected ClientConnection connection;
 
@@ -64,68 +70,31 @@
 	}
 
+	protected void onProtocolVersionNegotiated() {
+	}
+
+
 	public void setConnection(final ClientConnection connection) {
 		this.connection = connection;
-		this.connection.setConnectedFunctor(new StateFunctor() {
-			@Override
-			public void call(Exception e) {
-				if (e != null) {
-					fireRun(e);
-					return;
-				}
-				connection.negotiateProtocolVersion(new StateFunctor() {
+		final ExceptionResultHandler failure = new ExceptionResultHandler() {
+			@Override
+			public void handle(FramsticksException exception) {
+				log.fatal("failed to establish connection: ", exception);
+				// log.fatal("unsupported protocol version!\n minimal version is: " + "\nmanager protocol is: " + connection.getProtocolVersion());
+				Dispatching.drop(connection, RemoteInstance.this);
+				fireRun(exception);
+			}
+		};
+
+		this.connection.setConnectedFunctor(new AbstractStateFunctor(failure) {
+			@Override
+			public void call() {
+				connection.negotiateProtocolVersion(new AbstractStateFunctor(failure) {
 					@Override
-					public void call(Exception e) {
-						if (e != null) {
-							log.fatal("unsupported protocol version!\n minimal version is: " + "\nmanager protocol is: " + connection.getProtocolVersion());
-							Dispatching.drop(connection, RemoteInstance.this);
-							fireRun(e);
-							return;
-						}
-
-						dispatch(new RunAt<Instance>() {
-							@Override
-							public void run() {
-								resolveAndFetch("/simulator", new Future<Path>() {
-									@Override
-									public void result(Path path, Exception e) {
-										if (e != null) {
-											log.fatal("failed to resolve simulator node");
-											fireRun(e);
-											return;
-										}
-										assert isActive();
-										simulator = path;
-										fireRun(null);
-										log.info("resolved simulator node");
-
-										EventParam param = getParam(simulator, "running_changed", EventParam.class);
-										assert param != null;
-										connection.subscribe(simulator.getTextual() + "/" + param.getId(), RemoteInstance.this, new LoggingSubscriptionCallback<Instance>(log, "server running state change", new EventCallback() {
-											@Override
-											public void call(List<File> files) {
-												dispatch(new RunAt<Instance>() {
-													@Override
-													public void run() {
-														updateSimulationRunning();
-													}
-												});
-											}
-										}));
-										new PeriodicTask<Instance>(RemoteInstance.this, 1000) {
-											@Override
-											public void run() {
-												updateSimulationRunning();
-												again();
-											}
-										};
-									}
-								});
-							}
-						});
+					public void call() {
+						onProtocolVersionNegotiated();
 					}
 				});
 			}
 		});
-
 	}
 
@@ -136,48 +105,4 @@
 	}
 
-	public void setRunning(final boolean running) {
-		assert isActive();
-		//simulator.call(simulator.getParam(running ? "start" : "stop", ProcedureParam.class), new LoggingStateCallback(log, (running ? "starting" : "stopping") + " server"));
-	}
-
-	protected final UnaryListenersSet<Boolean> simulationRunningListeners = new UnaryListenersSet<Boolean>();
-
-	protected void updateSimulationRunning() {
-		assert isActive();
-		/*
-		fetchValue(simulator, getParam(simulator, "running", Param.class), new StateFunctor() {
-			@Override
-			public void call(Exception e) {
-				if (e != null) {
-					log.fatal("failed to query simulator running status: " + e);
-					return;
-				}
-
-				invokeLater(new Runnable() {
-					@Override
-					public void run() {
-						boolean value = bindAccess(simulator).get("running", Boolean.class);
-						log.trace("server running: " + value);
-						simulationRunningListeners.call(value);
-					}
-				});
-
-			}
-		});
-		 */
-	}
-
-	public void addRunningStateListener(UnaryFunctor<Boolean, Boolean> listener) {
-		assert isActive();
-		simulationRunningListeners.add(listener);
-	}
-
-	// public void disconnect() {
-	//	assert isActive();
-	//	if (connection.isConnected()) {
-	//		Dispatching.stop(connection, this);
-	//	}
-	// }
-
 	public final ClientConnection getConnection() {
 		return connection;
@@ -185,5 +110,5 @@
 
 	@Override
-	public void fetchValue(final Path path, final Param param, final StateFunctor stateFunctor) {
+	public void fetchValue(final Path path, final ValueParam param, final StateFunctor stateFunctor) {
 		assert isActive();
 		assert param != null;
@@ -194,12 +119,12 @@
 				assert isActive();
 				if (!response.getOk()) {
-					stateFunctor.call(new Exception(response.getComment()));
+					stateFunctor.handle(new FramsticksException().msg("failed to fetch value").arg("comment", response.getComment()));
 					return;
 				}
 				try {
-					processFetchedValues(path, response.getFiles());
-					stateFunctor.call(null);
-				} catch (Exception ex) {
-					stateFunctor.call(ex);
+					InstanceUtils.processFetchedValues(path, response.getFiles());
+					stateFunctor.call();
+				} catch (FramsticksException ex) {
+					stateFunctor.handle(ex);
 				}
 			}
@@ -209,15 +134,15 @@
 	protected final Map<String, Set<Future<FramsClass>>> infoRequests = new HashMap<String, Set<Future<FramsClass>>>();
 
-	protected void finishInfoRequest(String id, FramsClass result, Exception e) {
+	protected void finishInfoRequest(String id, FramsClass result, FramsticksException e) {
 		assert isActive();
 		Set<Future<FramsClass>> futures = infoRequests.get(id);
 		infoRequests.remove(id);
 		for (Future<FramsClass> f : futures) {
-			f.result(result, e);
-		}
-	}
-
-	@Override
-	protected void fetchInfo(final Path path, final Future<FramsClass> future) {
+			Future.passOrHandle(f, result, e);
+		}
+	}
+
+	@Override
+	public void fetchInfo(final Path path, final Future<FramsClass> future) {
 
 		final String name = path.getTop().getParam().getContainedTypeName();
@@ -238,28 +163,25 @@
 			public void process(Response response) {
 				assert isActive();
-				if (!response.getOk()) {
-					finishInfoRequest(name, null, new Exception(response.getComment()));
-					return;
-				}
-
-				assert response.getFiles().size() == 1;
-				assert path.isTheSame(response.getFiles().get(0).getPath());
-				FramsClass framsClass;
 				try {
-					framsClass = processFetchedInfo(response.getFiles().get(0));
-				} catch (ConstructionException e) {
-					log.fatal("could not read class info");
-					finishInfoRequest(name, null, new Exception("could not read class info"));
-					return;
-				}
-
-				CompositeParam thisParam = path.getTop().getParam();
-				if (!thisParam.isMatchingContainedName(framsClass.getId())) {
-					String mismatch = "class name mismatch: param=" + thisParam.getContainedTypeName() + " differs from fetched=" + framsClass.getId();
-					log.error(mismatch);
-					finishInfoRequest(name, null, new Exception(mismatch));
-					return;
-				}
-				finishInfoRequest(name, framsClass, null);
+					if (!response.getOk()) {
+						throw new FramsticksException().msg("invalid response").arg("comment", response.getComment());
+					}
+					if (response.getFiles().size() != 1) {
+						throw new FramsticksException().msg("invalid number of files in response").arg("files", response.getFiles().size());
+					}
+					if (!path.isTheSame(response.getFiles().get(0).getPath())) {
+						throw new FramsticksException().msg("path mismatch").arg("returned path", response.getFiles().get(0).getPath());
+					}
+					FramsClass framsClass = InstanceUtils.processFetchedInfo(RemoteInstance.this, response.getFiles().get(0));
+
+					CompositeParam thisParam = path.getTop().getParam();
+					if (!thisParam.isMatchingContainedName(framsClass.getId())) {
+						throw new FramsticksException().msg("framsclass id mismatch").arg("request", thisParam.getContainedTypeName()).arg("fetched", framsClass.getId());
+					}
+
+					finishInfoRequest(name, framsClass, null);
+				} catch (FramsticksException e) {
+					finishInfoRequest(name, null, e.arg("path", path));
+				}
 			}
 		});
@@ -276,15 +198,12 @@
 			public void process(Response response) {
 				assert isActive();
-				if (!response.getOk()) {
-					stateFunctor.call(new Exception(response.getComment()));
-					return;
-				}
 				try {
-					processFetchedValues(path, response.getFiles());
-					stateFunctor.call(null);
-				} catch (Exception ex) {
-					log.error("an exception occurred while loading: " + ex);
-					ex.printStackTrace();
-					stateFunctor.call(ex);
+					if (!response.getOk()) {
+						throw new FramsticksException().msg("failed to fetch values").arg("comment", response.getComment());
+					}
+					InstanceUtils.processFetchedValues(path, response.getFiles());
+					stateFunctor.call();
+				} catch (FramsticksException e) {
+					stateFunctor.handle(e);
 				}
 			}
@@ -294,35 +213,5 @@
 	@Override
 	public void resolve(final Path path, final Future<Path> future) {
-		assert isActive();
-		if (path.getTop().getObject() != null) {
-			if (getInfoFromCache(path) != null) {
-				future.result(path, null);
-				return;
-			}
-			findInfo(path, new Future<FramsClass>() {
-				@Override
-				public void result(FramsClass result, Exception e) {
-					if (e != null) {
-						future.result(null, e);
-						return;
-					}
-					future.result(path, null);
-				}
-			});
-			return;
-		}
-		findInfo(path, new Future<FramsClass>() {
-			@Override
-			public void result(FramsClass result, Exception e) {
-				assert isActive();
-				if (e != null) {
-					future.result(null, e);
-					return;
-				}
-				assert path.getTop().getParam().isMatchingContainedName(result.getId());
-				Path p = (path.getTop().getParam().getContainedTypeName() != null ? path : path.tryFindResolution());
-				future.result(createIfNeeded(p), null);
-			}
-		});
+		InstanceUtils.resolve(path, future);
 	}
 
@@ -330,5 +219,5 @@
 	protected void tryRegisterOnChangeEvents(final Path path) {
 		assert isActive();
-		AccessInterface access = bindAccess(path);
+		AccessInterface access = InstanceUtils.bindAccess(path);
 		if (!(access instanceof ListAccess)) {
 			return;
@@ -396,22 +285,23 @@
 	}
 
+	protected Future<Path> futureListChanger(final ListChange listChange, final String path) {
+		return new Future<Path>(Logging.logger(log, "failed to " + listChange, path)) {
+			@Override
+			protected void result(Path result) {
+				log.debug(listChange + ": " + result);
+				fireListChange(result, listChange);
+			}
+		};
+	}
+
 	protected void reactToChange(final Path path, final ListChange listChange) {
 		assert isActive();
 		log.debug("reacting to change " + listChange + " in " + path);
-		AccessInterface access = bindAccess(path);
+		AccessInterface access = InstanceUtils.bindAccess(path);
 		assert access != null;
 
 		if ((listChange.getAction() == ListChange.Action.Modify) && (listChange.getPosition() == -1)) {
 			final String p = path.getTextual();
-			resolveAndFetch(p, new Future<Path>() {
-				@Override
-				public void result(Path result, Exception e) {
-					if (e != null) {
-						log.error("failed to modify " + p + ": " + e);
-						return;
-					}
-					fireListChange(path, listChange);
-				}
-			});
+			InstanceUtils.resolveAndFetch(this, p, futureListChanger(listChange, p));
 			return;
 		}
@@ -420,54 +310,31 @@
 		assert childParam != null;
 		switch (listChange.getAction()) {
-		case Add: {
-			final String p = path.getTextual() + "/" + childParam.getId();
-			resolveAndFetch(p, new Future<Path>() {
-				@Override
-				public void result(Path result, Exception e) {
-					if (e != null) {
-						log.error("failed to add " + p + ": " + e);
-						return;
-					}
-					log.debug("added: " + result);
-					fireListChange(path, listChange);
-				}
-			});
-			break;
-		}
-		case Remove: {
-			access.set(childParam, null);
-			fireListChange(path, listChange);
-			break;
-		}
-		case Modify: {
-			final String p = path.getTextual() + "/" + childParam.getId();
-			resolveAndFetch(p, new Future<Path>() {
-				@Override
-				public void result(Path result, Exception e) {
-					if (e != null) {
-						log.error("failed to modify " + p + ": " + e);
-						return;
-					}
-					fireListChange(path, listChange);
-				}
-			});
-			break;
-		}
-		}
-	}
-
-	//TODO ValueParam
-	@Override
-	public void storeValue(final Path path, final Param param, final Object value, final StateFunctor stateFunctor) {
+			case Add: {
+				final String p = path.getTextual() + "/" + childParam.getId();
+				InstanceUtils.resolveAndFetch(this, p, futureListChanger(listChange, p));
+				break;
+			}
+			case Remove: {
+				access.set(childParam, null);
+				fireListChange(path, listChange);
+				break;
+			}
+			case Modify: {
+				final String p = path.getTextual() + "/" + childParam.getId();
+				InstanceUtils.resolveAndFetch(this, p, futureListChanger(listChange, p));
+				break;
+			}
+		}
+	}
+
+	@Override
+	public void storeValue(final Path path, final ValueParam param, final Object value, StateFunctor stateFunctor) {
 		assert isActive();
 
 		log.trace("storing value " + param + " for " + path);
-		connection.send(new SetRequest().value(value.toString()).field(param.getId()).path(path.getTextual()), this, new StateCallback<Instance>() {
-			@Override
-			public void call(Exception e) {
-				if (e == null) {
-					bindAccess(path).set((ValueParam) param, value);
-				}
-				stateFunctor.call(e);
+		connection.send(new SetRequest().value(value.toString()).field(param.getId()).path(path.getTextual()), this, new StateCallback<Instance>(stateFunctor) {
+			@Override
+			protected void callImpl() {
+				InstanceUtils.bindAccess(path).set((ValueParam) param, value);
 			}
 		});
@@ -504,6 +371,47 @@
 
 	@Override
-	public void call(Path path, ProcedureParam param, Object[] arguments, StateFunctor stateFunctor) {
-		throw new UnimplementedException();
+	public void call(@Nonnull final Path path, @Nonnull final ProcedureParam procedure, @Nonnull Object[] arguments, final Future<Object> future) {
+		assert isActive();
+		assert path.isResolved();
+
+		//TODO validate arguments type using params
+		connection.send(new CallRequest().procedure(procedure.getId()).arguments(Arrays.asList(arguments)).path(path.getTextual()), this, new ResponseCallback<Instance>() {
+			@Override
+			public void process(Response response) {
+				assert isActive();
+				try {
+					if (!response.getOk()) {
+						throw new FramsticksException().msg("failed to call procedure").arg("procedure", procedure).arg("comment", response.getComment());
+					}
+					// InstanceUtils.processFetchedValues(path, response.getFiles());
+					future.pass(null);
+				} catch (FramsticksException ex) {
+					future.handle(ex);
+				}
+			}
+		});
+
+	}
+
+	@Override
+	public Path create(Path path) {
+		assert isActive();
+		assert !path.isResolved();
+		Path resolved = path.tryFindResolution();
+		if (!resolved.isResolved()) {
+			log.debug("creating: " + path);
+			AccessInterface access = registry.prepareAccess(path.getTop().getParam());
+			assert access != null;
+			Object child = access.createAccessee();
+			assert child != null;
+			if (path.size() == 1) {
+				setRoot(new Node(getRoot().getParam(), child));
+			} else {
+				bindAccess(this, path.getUnder()).set(path.getTop().getParam(), child);
+			}
+			resolved = path.appendResolution(child);
+		}
+		tryRegisterOnChangeEvents(resolved);
+		return resolved;
 	}
 
