package com.framsticks.core; import com.framsticks.communication.*; import com.framsticks.params.*; import com.framsticks.params.types.ObjectParam; import com.framsticks.parsers.Loaders; import com.framsticks.parsers.MultiParamLoader; import com.framsticks.util.*; import com.framsticks.util.UnsupportedOperationException; import com.framsticks.util.dispatching.Dispatching; import com.framsticks.util.dispatching.Future; import com.framsticks.util.lang.Casting; import org.apache.log4j.Logger; import java.util.*; /** * @author Piotr Sniegowski */ public abstract class Instance extends Entity { private static final Logger log = Logger.getLogger(Instance.class.getName()); protected Node root; public Set listeners = new HashSet(); public Instance() { } @Override protected void run() { super.run(); root = new Node((CompositeParam)new ParamBuilder().setName("Instance").setId(name).setType("o").build(), null); com.framsticks.model.Package.register(registry); } protected void fetchInfo(Path path, Future future) { future.result(null, new UnsupportedOperationException()); } public void resolve(Path path, Future future) { assert isActive(); assert path.isOwner(this); if (path.getTop().getObject() != null) { future.result(path, null); return; } AccessInterface access = bindAccess(path.getUnder()); Object object = access.get(path.getTop().getParam(), Object.class); if (object == null) { future.result(path, null); return; } future.result(path.appendResolution(object), null); } public void fetchValue(Path path, Param param, StateFunctor stateFunctor) { stateFunctor.call(null); } public void fetchValues(Path path, StateFunctor stateFunctor) { stateFunctor.call(null); } protected void tryRegisterOnChangeEvents(Path path) { } public void storeValue(Path path, Param param, Object value, final StateFunctor stateFunctor) { assert isActive(); invokeLater(new Runnable() { @Override public void run() { stateFunctor.call(new UnsupportedOperationException()); } }); } protected void fireRun(Exception e) { for (InstanceListener l : this.listeners) { l.onRun(e); } } protected void fireStop(Exception e) { for (InstanceListener l : this.listeners) { l.onStop(e); } } public void addListener(final InstanceListener listener) { assert Dispatching.isThreadSafe(); Dispatching.invokeLaterOrNow(this, new Runnable() { @Override public void run() { listeners.add(listener); } }); } public void removeListener(final InstanceListener listener) { assert Dispatching.isThreadSafe(); Dispatching.invokeLaterOrNow(this, new Runnable() { @Override public void run() { listeners.remove(listener); } }); } protected void fireListChange(Path path, ListChange change) { assert isActive(); for (InstanceListener l : this.listeners) { l.onListChange(path, change); } } protected void fireFetch(Path path) { assert isActive(); for (InstanceListener l : this.listeners) { l.onFetch(path); } } public final FramsClass getInfoFromCache(Path path) { return getInfoFromCache(path.getTop().getParam().getContainedTypeName()); } public FramsClass getInfoFromCache(String id) { assert isActive(); return registry.getInfoFromCache(id); } protected Registry registry = new Registry(); public AccessInterface createAccess(String name) { assert isActive(); return registry.createAccess(name); } // TODO: make ValueParam public T get(Node node, Param childParam, Class type) { return bindAccess(node).get((ValueParam) childParam, type); } public void findInfo(final Path path, final Future future) { assert isActive(); final String name = path.getTop().getParam().getContainedTypeName(); final FramsClass framsClass = getInfoFromCache(name); if (framsClass != null) { log.trace("info for " + name + " found in cache"); future.result(framsClass, null); return; } fetchInfo(path, future); } public final AccessInterface bindAccess(Node node) { assert node.getObject() != null; AccessInterface access = registry.prepareAccess(node.getParam()); if (access == null) { log.error("missing access for: " + node.getParam()); return null; } access.select(node.getObject()); return access; } public final T getParam(Path path, String id, Class type) { return Casting.tryCast(type, registry.prepareAccess(path.getTop().getParam()).getParam(id)); } public final AccessInterface bindAccess(Path path) { assert path.isResolved(); return bindAccess(path.getTop()); } public void resolve(final String targetPath, final Future future) { assert isActive(); final Path path = getPath(targetPath); resolve(path, new Future() { @Override public void result(Path result, Exception e) { assert isActive(); if (e != null) { future.result(path, e); return; } if (path.isResolved(targetPath)) { future.result(path, null); return; } if (path.isResolved()) { future.result(path, new Exception("testing")); return; } resolve(targetPath, future); } }); } public void resolveAndFetch(final String targetPath, final Future future) { assert isActive(); resolve(targetPath, new Future() { @Override public void result(final Path path, Exception e) { if (e != null) { future.result(path, e); return; } assert path.isResolved(targetPath); fetchValues(path, new StateFunctor() { @Override public void call(Exception e) { future.result(path, e); } }); } }); } public Path createIfNeeded(String path) { Path p; while (!(p = getPath(path)).isResolved(path)) { create(p); } return p; } public Path createIfNeeded(Path path) { assert isActive(); if (path.isResolved()) { return path; } return create(path); } 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) { root = new Node(root.getParam(), child); } else { bindAccess(path.getUnder()).set(path.getTop().getParam(), child); } resolved = path.appendResolution(child); } tryRegisterOnChangeEvents(resolved); return resolved; } public FramsClass processFetchedInfo(File file) { assert isActive(); FramsClass framsClass = Loaders.loadFramsClass(file.getContent()); if ("/".equals(file.getPath())) { if (root.getParam().getContainedTypeName() == null) { root = new Node((CompositeParam)new ParamBuilder().setName("Instance").setId(name).setType("o " + framsClass.getId()).build(), root.getObject()); } } registry.putInfoIntoCache(framsClass); return framsClass; } public void processFetchedValues(Path path, List files) { assert 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(bindAccess(node)); loader.go(); fireFetch(path); // for (NodeListener l : listeners) { // l.onChange(this); // } return; } ListAccess listAccess = ((ListAccess)bindAccess(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()); Param param = new ParamBuilder().setType("o " + accessInterface.getId()).setId(id).build(); Object child = accessInterface.getSelected(); accessInterface.select(null); assert child != null; bindAccess(node).set((ValueParam) param, child); } } fireFetch(path); // for (NodeListener l : listeners) { // l.onChange(this); // } } catch (Exception e) { log.error("exception occurred while loading: " + e); } } public static Iterator splitPath(String path) { List list = new LinkedList(); for (String s : path.split("/")) { if (!s.isEmpty()) { list.add(s); } } return list.iterator(); } public Registry getRegistry() { return registry; } public Path getPath(String textual) { return new Path(this, textual); } public Path getRootPath() { return getPath("/"); } }