Skip to content

Instantly share code, notes, and snippets.

@kamekoopa
Last active December 16, 2015 06:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kamekoopa/5393617 to your computer and use it in GitHub Desktop.
Save kamekoopa/5393617 to your computer and use it in GitHub Desktop.
package filters;
import play.api.libs.iteratee.Iteratee;
import play.api.mvc.EssentialAction;
import play.api.mvc.EssentialAction$;
import play.api.mvc.EssentialFilter;
import play.api.mvc.RequestHeader;
import play.api.mvc.Result;
import play.libs.F.Function;
import scala.Function1;
import scala.runtime.AbstractFunction1;
abstract class EssentialJavaFilter implements EssentialFilter {
@Override
public EssentialAction apply(EssentialAction next) {
return newAction(filterFunc(next));
}
public abstract Function<RequestHeader, Iteratee<byte[], Result>> filterFunc(final EssentialAction next);
protected static EssentialAction newAction(final Function<RequestHeader, Iteratee<byte[], Result>> f){
return EssentialAction$.MODULE$.apply(toScalaFunc1(f));
}
protected static <A1, R> Function1<A1, R> toScalaFunc1(final Function<A1, R> f){
return new AbstractFunction1<A1, R>(){
@Override public R apply(A1 arg1) {
try{
return f.apply(arg1);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
};
}
}
import static play.core.Execution.internalContext;
import play.Logger;
import play.Logger.ALogger;
import play.api.libs.iteratee.Iteratee;
import play.api.mvc.AsyncResult;
import play.api.mvc.EssentialAction;
import play.api.mvc.EssentialAction$;
import play.api.mvc.EssentialFilter;
import play.api.mvc.PlainResult;
import play.api.mvc.RequestHeader;
import play.api.mvc.Result;
import scala.Function1;
import scala.runtime.AbstractFunction1;
public class HogeFilter implements EssentialFilter {
private final static ALogger logger = Logger.of("play");
/**
* @param next 本来実行すべきアクション?
*/
@Override
public EssentialAction apply(final EssentialAction next) {
final long start = System.currentTimeMillis();
logger.info("start!!!!!!!!!!!!!!!!!");
/*
* ScalaのEssentialActionオブジェクト↓を利用してフィルタ処理を追加した新しいアクションを定義する。
* object EssentialAction {
*
* def apply(f: RequestHeader => Iteratee[Array[Byte], Result]): EssentialAction = new EssentialAction {
* def apply(rh: RequestHeader) = f(rh)
* }
* }
*
* 引数には"RequestHeaderを引数に取り、Iteratee<byte[], Result>>を返す関数"を指定する
* RequestHeader(クライアントからのリクエスト)を、Iteratee(byte[](リクエストボディ)をResultに変換するレスポンス生成器)に変換する関数、の意味だと思う
*/
return EssentialAction$.MODULE$.apply(new AbstractFunction1<RequestHeader, Iteratee<byte[], Result>>(){
@Override public Iteratee<byte[], Result> apply(RequestHeader rh) {
/*
* ログ取り用関数。引数で受け取るResultはアクションの処理の結果として生成されたもの。
* ログを出すだけなのでResultは返り値としてそのままスルーする
* (レスポンス自体に変更は加えない)
*/
final Function1<Result, Result> logTime = new AbstractFunction1<Result, Result>() {
@Override public Result apply(Result result) {
long passedTime = System.currentTimeMillis() - start;
logger.info(String.format("passed time: %d", Long.valueOf(passedTime)));
return result;
}
};
/*
* リクエストヘッダに本来実行すべきアクションを適用した結果として得られる
* Iteratee(レスポンス生成器)のmapメソッドにさっきのログ取り用の関数を設定する
* mapメソッドに設定された関数は、IterateeがResultを生成し終わった段階で実行されるらしい
*/
return next.apply(rh).map(new AbstractFunction1<Result, Result>() {
@Override public Result apply(Result result) {
/*
* 生成されたResultがAsyncResultだった場合
* mapが呼ばれた時点で結果の生成が終わっていないっぽいので
* ログ取り用関数はasyncのmapメソッドへ設定する
*/
if(result instanceof AsyncResult){
AsyncResult async = (AsyncResult)result;
/*
* 第二引数のExecutionContextはimplicitなので
* Scalaからmapを呼ぶ場合は暗黙的に設定されるので明示的に指定する必要はないけど
* javaから指定する場合は明示的指定する必要がある。
* Scala力低いのでちゃんと追えなかったけど
* 多分internalContext()の戻り値が暗黙的に利用されてるんだよね…?
*/
return async.map(logTime, internalContext());
/*
* 非同期じゃないResulの場合は、普通にログ取り用関数をResulに適用した戻り値を返す
*/
}else{
PlainResult plain = (PlainResult) result;
return logTime.apply(plain);
}
}
});
}
});
}
}
package filters;
import static play.core.Execution.internalContext;
import play.Logger;
import play.Logger.ALogger;
import play.api.libs.iteratee.Iteratee;
import play.api.mvc.AsyncResult;
import play.api.mvc.EssentialAction;
import play.api.mvc.PlainResult;
import play.api.mvc.RequestHeader;
import play.api.mvc.Result;
import play.libs.F.Function;
import scala.Function1;
import scala.runtime.AbstractFunction1;
public class TimeScaleFilter extends EssentialJavaFilter {
private final static ALogger logger = Logger.of(TimeScaleFilter.class);
@Override
public Function<RequestHeader, Iteratee<byte[], Result>> filterFunc(final EssentialAction next) {
final long start = System.currentTimeMillis();
logger.info("action start");
return new Function<RequestHeader, Iteratee<byte[], Result>>() {
@Override public Iteratee<byte[], Result> apply(RequestHeader rh) {
/*
* ログ取り用関数。引数で受け取るResultはアクションの処理の結果として生成されたもの。
* ログを出すだけなのでResultは返り値としてそのままスルーする (レスポンス自体に変更は加えない)
*/
final Function1<Result, Result> logTime = new AbstractFunction1<Result, Result>() {
@Override public Result apply(Result result) {
long passedTime = System.currentTimeMillis() - start;
logger.info(String.format("passed time: %d", Long.valueOf(passedTime)));
return result;
}
};
/*
* リクエストヘッダに本来実行すべきアクションを適用した結果として得られる
* Iteratee(レスポンス生成器)のmapメソッドにさっきのログ取り用の関数を設定する
* mapメソッドに設定された関数は、IterateeがResultを生成し終わった段階で実行されるらしい
*/
return next.apply(rh).map(new AbstractFunction1<Result, Result>() {
@Override public Result apply(Result result) {
/*
* 生成されたResultがAsyncResultだった場合
* mapが呼ばれた時点で結果の生成が終わっていないっぽいので
* ログ取り用関数はasyncのmapメソッドへ設定する
*/
if (result instanceof AsyncResult) {
AsyncResult async = (AsyncResult) result;
/*
* 第二引数のExecutionContextはimplicitなので
* Scalaからmapを呼ぶ場合は暗黙的に設定されるので明示的に指定する必要はないけど
* javaから指定する場合は明示的指定する必要がある。 Scala力低いのでちゃんと追えなかったけど
* 多分internalContext()の戻り値が暗黙的に利用されてるんだよね…?
*/
return async.map(logTime, internalContext());
/*
* 非同期じゃないResulの場合は、普通にログ取り用関数をResulに適用した戻り値を返す
*/
} else {
PlainResult plain = (PlainResult) result;
return logTime.apply(plain);
}
}
});
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment