001package org.javasimon.callback.async; 002 003import org.javasimon.SimonManager; 004import org.javasimon.callback.Callback; 005import org.javasimon.proxy.Delegating; 006import org.javasimon.proxy.DelegatingMethodInvocation; 007 008import java.lang.reflect.Method; 009 010/** 011 * Callback factory, produces a callback wrapper to make any callback asynchronous. 012 * <p/> 013 * Example: {@code Callback myAsyncCallback=new AsyncCallbackProxy(myCallback).newProxy(); } 014 * <p/> 015 * The purpose of this wrapping callback is to prevent the wrapped callback 016 * from being executed on the main thread. This can be useful when a concrete 017 * callback is time consuming, to reduce the impact on application performances. 018 * <p/> 019 * It can be used to disable/enable, at runtime, a callback without removing it from 020 * the {@link SimonManager}: {@code asyncCallbackProxy.setExecutor(Executors.disabled);} 021 * 022 * @author gerald 023 */ 024public final class AsyncCallbackProxyFactory extends ExecutorProxyFactory<Callback> { 025 026 /** Interfaces implemented by callback proxy. */ 027 private static final Class[] PROXY_INTERFACES = new Class[]{Callback.class, Delegating.class}; 028 private final Method getDelegateMethod; 029 030 /** 031 * Constructor. 032 * 033 * @param delegate Wrapped object 034 */ 035 public AsyncCallbackProxyFactory(Callback delegate) { 036 super(delegate); 037 getDelegateMethod = findGetDelegateMethod(); 038 } 039 040 /** 041 * Constructor. 042 * 043 * @param delegate Wrapped object 044 * @param executor Executor used to run callback method, see {@link Executors} 045 */ 046 public AsyncCallbackProxyFactory(Callback delegate, Executor executor) { 047 super(delegate, executor); 048 getDelegateMethod = findGetDelegateMethod(); 049 } 050 051 /** 052 * Finds {@link Delegating#getDelegate()} method. 053 * 054 * @return delegate method 055 */ 056 private Method findGetDelegateMethod() { 057 try { 058 return Delegating.class.getDeclaredMethod("getDelegate", new Class[0]); 059 } catch (NoSuchMethodException | SecurityException noSuchMethodException) { 060 throw new IllegalStateException("getDelegate method not found on Delegating interface", noSuchMethodException); 061 } 062 } 063 064 /** 065 * Creates a callback proxy. 066 * 067 * @param classLoader Class loader 068 * @return Callback proxy. 069 */ 070 public Callback newProxy(ClassLoader classLoader) { 071 return (Callback) newProxy(classLoader, PROXY_INTERFACES); 072 } 073 074 /** 075 * Creates a callback proxy. 076 * The class loader for current thread is used as default class loader. 077 * 078 * @return Callback proxy. 079 */ 080 public Callback newProxy() { 081 return (Callback) newProxy(PROXY_INTERFACES); 082 } 083 084 @Override 085 protected Object invoke(DelegatingMethodInvocation<Callback> delegatingMethodInvocation) throws Throwable { 086 Object result; 087 if (delegatingMethodInvocation.getMethod().equals(getDelegateMethod)) { 088 result = getDelegate(); 089 } else { 090 result = super.invoke(delegatingMethodInvocation); 091 } 092 return result; 093 } 094}