package com.fernandocejas.frodo.aspect; import com.fernandocejas.frodo.internal.Counter; import com.fernandocejas.frodo.internal.MessageManager; import com.fernandocejas.frodo.internal.StopWatch; import com.fernandocejas.frodo.joinpoint.FrodoJoinPoint; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import rx.Subscriber; @Aspect public class LogSubscriber { private static final String CLASS = "within(@com.fernandocejas.frodo.annotation.RxLogSubscriber *) && if()"; private static final String METHOD_ON_START = "execution(void *.onStart())"; private static final String METHOD_ON_NEXT = "execution(void *.onNext(..))"; private static final String METHOD_ON_ERROR = "execution(void *.onError(java.lang.Throwable)) && args(throwable)"; private static final String METHOD_ON_COMPLETED = "execution(void *.onCompleted())"; private static final String METHOD_REQUEST = "call(void *.request(long)) && args(numberOfItems)"; private static final String METHOD_UN_SUBSCRIBE = "call(void *.unsubscribe())"; private final Counter counter; private final StopWatch stopWatch; private final MessageManager messageManager; private boolean isFirstElementEmitted = true; public LogSubscriber() { this(new Counter(), new StopWatch(), new MessageManager()); } public LogSubscriber(Counter counter, StopWatch stopWatch, MessageManager messageManager) { this.counter = counter; this.stopWatch = stopWatch; this.messageManager = messageManager; } @Pointcut(CLASS) public static boolean classAnnotatedWithRxLogSubscriber(JoinPoint joinPoint) { return joinPoint.getTarget() instanceof Subscriber; } @Pointcut(METHOD_ON_START) public void onStartMethodExecution() { } @Pointcut(METHOD_ON_NEXT) public void onNextMethodExecution() { } @Pointcut(METHOD_ON_ERROR) public void onErrorMethodExecution(Throwable throwable) { } @Pointcut(METHOD_ON_COMPLETED) public void onCompletedMethodExecution() { } @Pointcut(METHOD_REQUEST) public void onRequestMethodCall(long numberOfItems) { } @Pointcut(METHOD_UN_SUBSCRIBE) public void onUnsubscribeMethodCall() { } @Before("classAnnotatedWithRxLogSubscriber(joinPoint) && onStartMethodExecution()") public void beforeOnStartExecution(JoinPoint joinPoint) { messageManager.printSubscriberOnStart(joinPoint.getTarget().getClass().getSimpleName()); } @Before("classAnnotatedWithRxLogSubscriber(joinPoint) && onNextMethodExecution()") public void beforeOnNextExecution(JoinPoint joinPoint) { countAndMeasureTime(); final FrodoJoinPoint frodoJoinPoint = new FrodoJoinPoint(joinPoint); final Object value = frodoJoinPoint.getMethodParamValuesList().isEmpty() ? null : frodoJoinPoint.getMethodParamValuesList().get(0); messageManager.printSubscriberOnNext(joinPoint.getTarget().getClass().getSimpleName(), value, Thread.currentThread().getName()); } @After(value = "classAnnotatedWithRxLogSubscriber(joinPoint) && onErrorMethodExecution(throwable)", argNames = "joinPoint,throwable") public void afterOnErrorExecution(JoinPoint joinPoint, Throwable throwable) { stopWatch.stop(); messageManager.printSubscriberOnError(joinPoint.getTarget().getClass().getSimpleName(), throwable.toString(), stopWatch.getTotalTimeMillis(), counter.tally()); resetCounters(); } @Before("classAnnotatedWithRxLogSubscriber(joinPoint) && onCompletedMethodExecution()") public void beforeOnCompletedExecution(JoinPoint joinPoint) { stopWatch.stop(); messageManager.printSubscriberOnCompleted(joinPoint.getTarget().getClass().getSimpleName(), stopWatch.getTotalTimeMillis(), counter.tally()); resetCounters(); } @After("classAnnotatedWithRxLogSubscriber(joinPoint) && onUnsubscribeMethodCall()") public void afterUnsubscribeMethodCall(JoinPoint joinPoint) { messageManager.printSubscriberUnsubscribe(joinPoint.getTarget().getClass().getSimpleName()); } @After("classAnnotatedWithRxLogSubscriber(joinPoint) && onRequestMethodCall(numberOfItems)") public void afterRequestMethodCall(JoinPoint joinPoint, long numberOfItems) { messageManager.printSubscriberRequestedItems(joinPoint.getTarget().getClass().getSimpleName(), numberOfItems); } private void countAndMeasureTime() { counter.increment(); if (isFirstElementEmitted) { stopWatch.start(); } isFirstElementEmitted = false; } private void resetCounters() { isFirstElementEmitted = true; counter.clear(); stopWatch.reset(); } }