package com.google.sitebricks.channel; import com.google.inject.Binder; import com.google.inject.Injector; import com.google.sitebricks.client.Transport; import javax.inject.Inject; import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * @author dhanji@gmail.com (Dhanji R. Prasanna) */ class ObserverWrapper { static final String DEFAULT = "__$_sb:def_"; private final Class<?> type; private Injector injector; private final Map<String, MethodDispatcher> receivers; public ObserverWrapper(String event, Class<?> type, Binder binder) { this.type = type; this.receivers = new HashMap<String, MethodDispatcher>(); for (Method method : type.getDeclaredMethods()) { Observe observe = method.getAnnotation(Observe.class); if (observe != null) { if (method.getParameterTypes().length != 1) binder.addError("@Observe method must take exactly one argument: " + method); if (method.getReturnType() != void.class) binder.addError("@Observe method must not return any values: " + method); receivers.put(event, new MethodDispatcher(observe, method)); } } } public void dispatch(String event, String data) { if (event == null) event = DEFAULT; MethodDispatcher method = receivers.get(event); Object instance = injector.getInstance(type); Transport transport = injector.getInstance(method.observe.value()); try { Object in = transport.in(new ByteArrayInputStream(data.getBytes()), method.method.getParameterTypes()[0]); method.method.invoke(instance, in); } catch (IllegalAccessException e) { throw new RuntimeException("Dispatch error in @Observe method: " + method, e); } catch (InvocationTargetException e) { throw new RuntimeException("Dispatch error in @Observe method: " + method, e); } catch (IOException e) { throw new RuntimeException("Dispatch error in @Observe method: " + method, e); } } @Inject void init(Injector injector) { this.injector = injector; } private static class MethodDispatcher { private final Observe observe; private final Method method; private MethodDispatcher(Observe observe, Method method) { this.observe = observe; this.method = method; } } }