package com.framsticks.remote; import static com.framsticks.core.InstanceUtils.*; import com.framsticks.core.Node; import com.framsticks.core.Path; import com.framsticks.params.AccessInterface; import com.framsticks.params.CompositeParam; import com.framsticks.params.FramsClass; import com.framsticks.core.Instance; import com.framsticks.util.dispatching.Future; import com.framsticks.util.FramsticksException; import com.framsticks.util.Logging; import com.framsticks.util.StateFunctor; import com.framsticks.util.Stopwatch; import org.apache.log4j.Logger; import static com.framsticks.util.lang.Containers.filterInstanceof; import com.framsticks.util.dispatching.RunAt; /** * @author Piotr Sniegowski */ public class RecursiveFetcher { private final static Logger log = Logger.getLogger(RecursiveFetcher.class.getName()); protected final Instance instance; protected final StateFunctor stateFunctor; protected int dispatched; protected final Stopwatch stopwatch = new Stopwatch(); public RecursiveFetcher(Instance instance, final Path path, StateFunctor stateFunctor) { this.instance = instance; this.stateFunctor = stateFunctor; dispatched = 1; process(path); } protected void finished() { assert instance.isActive(); log.info("recursively fetched in " + stopwatch); stateFunctor.call(); } protected void process(final Path path) { assert instance.isActive(); if (path == null || !path.isResolved()) { log.warn("path " + path + " is not resolved - skipping"); } else { AccessInterface access = bindAccess(path); FramsClass framsClass = access.getFramsClass(); assert framsClass != null; for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) { Object child = access.get(p, Object.class); final Path childPath = path.appendNode(new Node(p, child)); if (childPath.isResolved() && getInfoFromCache(childPath) != null) { ++dispatched; instance.dispatch(new RunAt() { @Override public void run() { fetch(childPath); } }); continue; } ++dispatched; instance.resolve(childPath, new Future(Logging.logger(log, "resolve", RecursiveFetcher.this)) { @Override protected void result(Path result) { assert instance.isActive(); fetch(result); } }); } } --dispatched; if (dispatched == 0) { finished(); } } protected void fetch(final Path path) { instance.fetchValues(path, new StateFunctor() { @Override public void handle(FramsticksException e) { log.error("failed to fetch values for " + path + ": " + e); process(null); } @Override public void call() { process(path); } }); } }