package com.framsticks.remote; 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.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(null); } 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 = instance.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() && instance.getInfoFromCache(childPath) != null) { ++dispatched; instance.dispatch(new RunAt() { @Override public void run() { fetch(childPath); } }); continue; } ++dispatched; instance.resolve(childPath, new Future() { @Override public void result(Path result, Exception e) { assert instance.isActive(); if (e != null) { log.error(e); return; } fetch(result); } }); } } --dispatched; if (dispatched == 0) { finished(); } } protected void fetch(final Path path) { instance.fetchValues(path, new StateFunctor() { @Override public void call(Exception e) { if (e != null) { log.error("failed to fetch values for " + path + ": " + e); process(null); return; } process(path); } }); } }