package io.hummer.prefetch.impl; import io.hummer.prefetch.PrefetchingService.ServiceInvocation; import io.hummer.prefetch.context.Context; import io.hummer.prefetch.context.Time; import io.hummer.util.coll.Pair; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.SimpleBindings; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlValue; import com.sun.phobos.script.javascript.RhinoScriptEngineFactory; /** * Defines a (typically repeated) service usage pattern. * @author Waldemar Hummer (hummer@dsg.tuwien.ac.at) */ @XmlType public class UsagePattern { @XmlAttribute(name="len") public Double timeLength; @XmlValue public String expression; private static ScriptEngine eng = new RhinoScriptEngineFactory().getScriptEngine(); /** * Default c'tor, required by JAXB. */ public UsagePattern() {} public UsagePattern(String expression) { this(expression, null); } public UsagePattern(String expression, Double timeLength) { this.expression = expression; this.timeLength = timeLength; } public double predictUsage(double time) { if(timeLength != null) { time %= timeLength; } Map<String,Object> map = new HashMap<>(); map.put("x", time); map.put("time", time); Bindings bindings = new SimpleBindings(map); try { Object d = evalJS(expression, bindings); return Double.parseDouble("" + d); } catch (Exception e) { throw new RuntimeException(e); } } public static class UsagePatternPredictionBased extends UsagePattern { public Context<Object> context; InvocationPredictor predictor; double valueIfInvocationPredicted; public UsagePatternPredictionBased(InvocationPredictor predictor, Context<Object> ctx, double valueIfInvocationPredicted) { this.predictor = predictor; this.context = ctx; this.valueIfInvocationPredicted = valueIfInvocationPredicted; } public double predictUsage(double time) { List<Pair<Context<Object>, ServiceInvocation>> invs = predictor.predictInvocations(context, new Time(time)); if(!invs.isEmpty()) { return valueIfInvocationPredicted; } return 0; } public void setContext(Context<Object> context) { this.context = context; } } public static UsagePattern predictionBased(InvocationPredictor pred, Context<Object> ctx, double valueIfInvocationPredicted) { return new UsagePatternPredictionBased(pred, ctx, valueIfInvocationPredicted); } @Deprecated public static UsagePattern periodic( double repeatTimeSecs, double amount, double durationSecs) { return new UsagePattern( "x < " + (repeatTimeSecs - durationSecs) + " ? 0 : " + "x < " + repeatTimeSecs + " ? " + amount + " : " + "0", repeatTimeSecs); } @Deprecated public static UsagePattern constant(double amount) { return new UsagePattern("" + amount); } public static UsagePattern combine(final UsagePattern ... patterns) { return new UsagePattern(null) { @Override public double predictUsage(double time) { double result = 0; for(UsagePattern p : patterns) result += p.predictUsage(time); return result; } }; } private static Object evalJS(String js, Bindings bindings) { try { return eng.eval(js, bindings); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { UsagePattern p1 = periodic(60, 10, 5); System.out.println(p1.predictUsage(123.45)); System.out.println(p1.predictUsage(118)); System.out.println(p1.predictUsage(56)); UsagePattern p2 = constant(110); System.out.println(p2.predictUsage(123.45)); UsagePattern p3 = combine(p1, p2); System.out.println(p3.predictUsage(118)); } }