package com.framsticks.remote; import com.framsticks.params.Access; import com.framsticks.params.CompositeParam; import com.framsticks.structure.Node; import com.framsticks.structure.Path; import com.framsticks.structure.Tree; import com.framsticks.util.dispatching.FutureHandler; import com.framsticks.util.dispatching.Future; import com.framsticks.util.dispatching.ThrowExceptionHandler; import com.framsticks.util.FramsticksException; import com.framsticks.util.Logging; import com.framsticks.util.Stopwatch; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import static com.framsticks.structure.TreeOperations.*; 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 = LogManager.getLogger(RecursiveFetcher.class.getName()); protected final Tree tree; protected final FutureHandler future; protected int dispatched; protected final Stopwatch stopwatch = new Stopwatch(); public RecursiveFetcher(Tree tree, final Path path, FutureHandler future) { this.tree = tree; this.future = future; dispatched = 1; process(path); } protected void finished() { assert tree.isActive(); log.info("recursively fetched in {}", stopwatch); future.pass(null); } protected void process(final Path path) { assert tree.isActive(); if (path == null || !path.isResolved()) { log.warn("path {} is not resolved - skipping", path); } else { Access access = bindAccess(path); for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) { Object child = access.get(p, Object.class); final Path childPath = path.appendNode(new Node(path.getTree(), p, child)); if (childPath.isResolved() && getInfoFromCache(childPath) != null) { ++dispatched; tree.dispatch(new RunAt(ThrowExceptionHandler.getInstance()) { @Override protected void runAt() { fetch(childPath); } }); continue; } ++dispatched; tree.get(childPath, new Future(Logging.logger(log, "resolve", RecursiveFetcher.this)) { @Override protected void result(Path result) { assert tree.isActive(); fetch(result); } }); } } --dispatched; if (dispatched == 0) { finished(); } } protected void fetch(final Path path) { tree.get(path, new FutureHandler() { @Override public void handle(FramsticksException e) { log.error("failed to fetch values for {}: ", path, e); process(null); } @Override protected void result(Path result) { process(result); } }); } }