package io.hummer.prefetch.context; import io.hummer.prefetch.context.Path.PathPoint; import io.hummer.util.log.LogUtil; import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; /** * "Predicts" and generates future instances of the context information. * @author Waldemar Hummer */ public interface ContextPredictor<T> { List<Time> predictContextChanges(Context<T> currentContext, Time fromTime, Time toTime); Context<T> predict(Context<T> currentContext, Time time); /** * @param currentContext * @param fromTime including * @param toTime excluding * @return */ List<Context<T>> predictContexts( Context<Object> currentContext, Time fromTime, Time toTime); /** * Default implementation based on time, path, location and network availability */ public static class DefaultPredictor implements ContextPredictor<Object> { protected static final Logger LOG = LogUtil.getLogger(); public Context<Object> predict(Context<Object> currentContext, Time time) { double t = time.time; Context<Object> copy = currentContext.copy(); copy.setContextAttribute(Context.ATTR_TIME, time); Path path = (Path)copy.getAttribute(Context.ATTR_PATH); //Path futurePath = (Path)copy.getAttribute(Context.ATTR_FUTURE_PATH); if(path != null) { copy.setContextAttribute(Context.ATTR_FUTURE_PATH, path.getFuturePathAt(t)); PathPoint current = path.getLocationAtTime(t); if(current != null) { copy.setContextAttribute(Context.ATTR_LOCATION, current); copy.setContextAttribute(Context.ATTR_LOCATION_LAT, current.coordinates.lat); copy.setContextAttribute(Context.ATTR_LOCATION_LON, current.coordinates.lon); copy.setContextAttribute(Context.ATTR_NETWORK_AVAILABLE, current.cellNetworkCoverage.hasSufficientCoverage()); } else { LOG.warn("Cannot find location at time " + t + " in path " + path.points); copy.setContextAttribute(Context.ATTR_LOCATION, null); copy.setContextAttribute(Context.ATTR_LOCATION_LAT, null); copy.setContextAttribute(Context.ATTR_LOCATION_LON, null); copy.setContextAttribute(Context.ATTR_NETWORK_AVAILABLE, false); } } return copy; } public List<Context<Object>> predictContexts( Context<Object> currentContext, Time fromTime, Time toTime) { List<Context<Object>> result = new LinkedList<Context<Object>>(); //System.out.println("changes: " + predictContextChanges(currentContext, fromTime, toTime)); //System.out.println(currentContext); for(Time t : predictContextChanges(currentContext, fromTime, toTime)) { result.add(predict(currentContext, t)); } LOG.trace("predicted contexts from " + fromTime + " to " + toTime + ": " + result.size()); return result; } public List<Time> predictContextChanges( Context<Object> currentContext, Time fromTime, Time toTime) { List<Time> result = new LinkedList<Time>(); Path path = (Path)currentContext.getAttribute(Context.ATTR_PATH); if(path != null) { for(PathPoint p : path.points) { if(p.time.isBetween(fromTime, toTime, false)) { result.add(p.time); } } } if(LOG.isDebugEnabled()) LOG.debug("times ContextChangeBased: " + fromTime + "-" + toTime + ": " + result); return result; } } public static class DefaultPredictorWithUpdateInterval extends DefaultPredictor { private double updateSeconds = 60; // private double timeInterval = 10; // TODO remove?? public DefaultPredictorWithUpdateInterval() { } public DefaultPredictorWithUpdateInterval(double updateSeconds, double timeInterval) { this.updateSeconds = updateSeconds; // this.timeInterval = timeInterval; } public List<Time> predictContextChanges(Context<Object> currentContext, Time fromTime, Time toTime) { List<Time> result = new LinkedList<Time>(); Path path = (Path)currentContext.getAttribute(Context.ATTR_PATH); double lastPathTime = -1; if(path != null) { if(path.points.isEmpty()) { return result; } lastPathTime = path.points.get(path.size() - 1).time.time; } double start = (double)((int)(fromTime.time / updateSeconds)) * updateSeconds; /* note: t < toTime.time is essential here, do NOT use t <= toTime.time */ for(double t = start; t < toTime.time; t += updateSeconds) { if(lastPathTime >= 0 && t > lastPathTime) { break; } if(t >= fromTime.time) { result.add(new Time(t)); //result.add(new Time(t + timeInterval)); // TODO revise! } } if(LOG.isDebugEnabled()) LOG.debug("times UpdateInterval: " + fromTime + "-" + toTime + ": " + result); return result; } } }