package com.framsticks.core; import java.util.List; import javax.annotation.Nonnull; import org.apache.log4j.Logger; import com.framsticks.communication.File; import com.framsticks.params.AccessInterface; import com.framsticks.params.CompositeParam; import com.framsticks.params.FramsClass; import com.framsticks.params.ListAccess; import com.framsticks.params.Param; import com.framsticks.params.ValueParam; import com.framsticks.params.types.ObjectParam; import com.framsticks.params.types.ProcedureParam; import com.framsticks.parsers.Loaders; import com.framsticks.parsers.MultiParamLoader; import com.framsticks.util.AbstractStateFunctor; import com.framsticks.util.FramsticksException; import com.framsticks.util.StateFunctor; import com.framsticks.util.dispatching.Future; import com.framsticks.util.dispatching.RunAt; import static com.framsticks.util.dispatching.Dispatching.*; public final class InstanceUtils { private static final Logger log = Logger.getLogger(InstanceUtils.class.getName()); private InstanceUtils() { } public static @Nonnull FramsClass processFetchedInfo(Instance instance, File file) { assert instance.isActive(); FramsClass framsClass = Loaders.loadFramsClass(file.getContent()); if ("/".equals(file.getPath())) { if (instance.getRoot().getParam().getContainedTypeName() == null) { instance.setRoot(new Node(Param.build().name("Instance").id(instance.getName()).type("o " + framsClass.getId()).finish(CompositeParam.class), instance.getRoot().getObject())); } } instance.putInfoIntoCache(framsClass); return framsClass; } public static void findInfo(final Path path, final Future future) { Instance instance = path.getInstance(); assert instance.isActive(); final String name = path.getTop().getParam().getContainedTypeName(); final FramsClass framsClass = instance.getInfoFromCache(name); if (framsClass != null) { log.trace("info for " + name + " found in cache"); future.pass(framsClass); return; } instance.fetchInfo(path, future); } public static void processFetchedValues(Path path, List files) { Instance instance = path.getInstance(); assert instance.isActive(); assert files.size() == 1; assert path.isTheSame(files.get(0).getPath()); Node node = path.getTop(); MultiParamLoader loader = new MultiParamLoader(); loader.setNewSource(files.get(0).getContent()); loader.addBreakCondition(MultiParamLoader.Status.AfterObject); try { if (node.getParam() instanceof ObjectParam) { loader.addAccessInterface(InstanceUtils.bindAccess(instance, node)); loader.go(); instance.notifyOfFetch(path); return; } ListAccess listAccess = ((ListAccess) InstanceUtils.bindAccess(instance, node)); assert listAccess != null; listAccess.clearValues(); AccessInterface elementAccess = listAccess.getElementAccess(); loader.addAccessInterface(elementAccess); MultiParamLoader.Status status; while ((status = loader.go()) != MultiParamLoader.Status.Finished) { if (status == MultiParamLoader.Status.AfterObject) { AccessInterface accessInterface = loader.getLastAccessInterface(); String id = listAccess.computeIdentifierFor(accessInterface.getSelected()); //TODO listAccessParam Param param = Param.build().forAccess(accessInterface).id(id).finish(); Object child = accessInterface.getSelected(); accessInterface.select(null); assert child != null; InstanceUtils.bindAccess(instance, node).set((ValueParam) param, child); } } instance.notifyOfFetch(path); } catch (Exception e) { log.error("exception occurred while loading: " + e); } } public static void resolveAndFetch(final Instance instance, final String targetPath, final Future future) { assert instance.isActive(); InstanceUtils.resolve(instance, targetPath, new Future(future) { @Override protected void result(final Path path) { assert path.isResolved(targetPath); //TODO Future instance.fetchValues(path, new AbstractStateFunctor(future) { @Override public void call() { future.pass(path); } }); } }); } public static void resolve(final Path path, final Future future) { final Instance instance = path.getInstance(); assert instance.isActive(); if (path.getTop().getObject() != null) { if (getInfoFromCache(path) != null) { future.pass(path); return; } InstanceUtils.findInfo(path, new Future(future) { @Override protected void result(FramsClass result) { future.pass(path); } }); return; } InstanceUtils.findInfo(path, new Future(future) { @Override protected void result(FramsClass result) { assert instance.isActive(); assert path.getTop().getParam().isMatchingContainedName(result.getId()); Path p = (path.getTop().getParam().getContainedTypeName() != null ? path : path.tryFindResolution()); future.pass(InstanceUtils.createIfNeeded(p)); } }); } public static Path createIfNeeded(Instance instance, String path) { assert instance.isActive(); Path p; while (!(p = Path.to(instance, path)).isResolved(path)) { instance.create(p); } return p; } public static Path createIfNeeded(Path path) { Instance instance = path.getInstance(); assert instance.isActive(); if (path.isResolved()) { return path; } return instance.create(path); } public static @Nonnull AccessInterface bindAccess(Instance instance, String path) { return bindAccess(Path.to(instance, path)); } public static @Nonnull AccessInterface bindAccess(Instance instance, Node node) { assert instance.isActive(); assert node.getObject() != null; try { AccessInterface access = instance.prepareAccess(node.getParam()); if (access == null) { throw new FramsticksException().msg("failed to prepare access for param").arg("param", node.getParam()); } return access.select(node.getObject()); } catch (FramsticksException e) { throw new FramsticksException().msg("failed to prepare access for param").arg("param", node.getParam()).cause(e); // log.error("failed to bind access for " + node.getParam() + ": " + e); } } public static @Nonnull AccessInterface bindAccess(Path path) { assert path.getInstance().isActive(); path.assureResolved(); return bindAccess(path.getInstance(), path.getTop()); } public static void storeValue(final Path path, final ValueParam param, final Object value, final StateFunctor stateFunctor) { final Instance instance = path.getInstance(); dispatchIfNotActive(instance, new RunAt() { @Override public void run() { instance.storeValue(path, param, value, stateFunctor); } }); } public static void call(final Path path, final ProcedureParam param, final Object[] arguments, final Future future) { final Instance instance = path.getInstance(); dispatchIfNotActive(instance, new RunAt() { @Override public void run() { instance.call(path, param, arguments, future); } }); } /** This might not be correct. */ public static void resolve(final Instance instance, final String targetPath, final Future future) { dispatchIfNotActive(instance, new RunAt() { @Override public void run() { instance.resolve(Path.to(instance, targetPath), new Future(future) { @Override protected void result(Path result) { assert result.getInstance().isActive(); if (result.isResolved(targetPath)) { future.pass(result); return; } resolve(result.getInstance(), targetPath, future); } }); } }); } public static FramsClass getInfoFromCache(Path path) { assert path.getInstance().isActive(); return path.getInstance().getInfoFromCache(path.getTop().getParam().getContainedTypeName()); } }