package com.arpnetworking.utils; import play.Logger; import play.libs.F; import play.mvc.Action; import play.mvc.Http; import play.mvc.Result; import play.mvc.With; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Action to intercept and time (query log) requests * * @author barp */ public class Timed { @With(TimedAction.class) @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Logged { String counterName() default ""; } public static class TimedAction extends Action<Logged> { @SuppressWarnings("unchecked") public F.Promise<Result> call(Http.Context ctx) { F.Promise<Result> result = null; final Counter counter; if (ctx.args.containsKey("query-log")) { counter = (Counter)ctx.args.get("query-log"); } else { counter = new Counter(); ctx.args.put("query-log", counter); } String counterName = configuration.counterName(); if (counterName.equals("")) { counterName = ctx.request().path(); //remove any integer based resource identifiers String oldCounter = counterName; counterName = counterName.replaceAll("/\\d+", ""); if (!oldCounter.equals(counterName)) { Logger.debug("Counter name changed to " + counterName + " from " + oldCounter); } } final String finalCounterName = counterName; try { counter.startTimer(finalCounterName); result = delegate.call(ctx); result.map(new F.Function<Result, Void>() { @Override public Void apply(final Result result) throws Throwable { counter.stopTimer(finalCounterName); counter.saveCounters(); return null; } }).onFailure(new F.Callback<Throwable>() { @Override public void invoke(final Throwable throwable) throws Throwable { counter.stopTimer(finalCounterName); counter.saveCounters(); } }); return result; } catch(RuntimeException e) { counter.stopTimer(finalCounterName); throw e; } catch(Throwable t) { counter.stopTimer(finalCounterName); throw new RuntimeException(t); } } } }