Java tutorial
/* Copyright 2011-2013 the original author or authors: * * Marc Palmer (marc@grailsrocks.com) * Stphane Maldini (smaldini@vmware.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.grails.plugin.platform.events.registry; import groovy.lang.Closure; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.log4j.Logger; import org.grails.plugin.platform.events.EventMessage; import org.grails.plugin.platform.events.ListenerId; import org.grails.plugin.platform.events.utils.EventsUtils; import org.springframework.util.ReflectionUtils; /** * @author Stephane Maldini <smaldini@vmware.com> * @version 1.0 * @file * @date 02/01/12 * @section DESCRIPTION * <p/> * [Does stuff] */ public class DefaultEventsRegistry implements EventsRegistry { private static final Logger log = Logger.getLogger(DefaultEventsRegistry.class); private Set<ListenerHandler> listeners = new HashSet<ListenerHandler>(); /* API */ public String on(String namespace, String topic, @SuppressWarnings("rawtypes") Closure callback) { return registerHandler(callback, namespace, topic); } public String on(String namespace, String topic, Object bean, String callbackName) { return registerHandler(bean, ReflectionUtils.findMethod(bean.getClass(), callbackName), namespace, topic); } public String on(String namespace, String topic, Object bean, Method callback) { return registerHandler(bean, callback, namespace, topic); } public int removeListeners(String callbackId) { ListenerId listener = ListenerId.parse(callbackId); if (listener == null) { return 0; } synchronized (listeners) { for (ListenerHandler _listener : findAll(listener)) { listeners.remove(_listener); } } return listeners.size(); } public int countListeners(String callbackId) { ListenerId listener = ListenerId.parse(callbackId); if (listener == null) { return 0; } return findAll(listener).size(); } /* INTERNAL */ private String registerHandler(@SuppressWarnings("rawtypes") Closure callback, String namespace, String topic) { if (log.isDebugEnabled()) { log.debug("Registering event handler [" + callback.getClass() + "] for topic [" + topic + "]"); } ListenerId listener = ListenerId.build(namespace, topic, callback); ListenerHandler handler = new ListenerHandler(callback, ReflectionUtils.findMethod(callback.getClass(), "call", Object.class), listener); synchronized (listeners) { listeners.add(handler); } return listener.toString(); } private String registerHandler(Object bean, Method callback, String namespace, String topic) { if (log.isDebugEnabled()) { log.debug("Registering event handler on bean [" + bean + "] method [" + callback + "] for topic [" + topic + "]"); } ListenerId listener = ListenerId.build(namespace, topic, EventsUtils.unproxy(bean), callback); ListenerHandler handler = new ListenerHandler(bean, callback, listener); synchronized (listeners) { listeners.add(handler); } return listener.toString(); } private Set<ListenerHandler> findAll(ListenerId listener) { if (log.isDebugEnabled()) { log.debug("Finding listeners matching listener id [" + listener.toString() + "]"); } Set<ListenerHandler> listeners = new HashSet<ListenerHandler>(); for (ListenerHandler _listener : this.listeners) { if (listener.matches(_listener.getListenerId())) { listeners.add(_listener); } } return listeners; } public InvokeResult invokeListeners(EventMessage<?> evt) { if (log.isDebugEnabled()) { log.debug("Invoking listeners for event [" + evt.getEvent() + "] namespaced on [" + evt.getNamespace() + "] with data [" + evt.getData() + "]"); } ListenerId listener = new ListenerId(evt.getNamespace(), evt.getEvent()); Set<ListenerHandler> listeners = findAll(listener); if (log.isDebugEnabled()) { log.debug("Found " + listeners.size() + " listeners for event [" + evt.getEvent() + "] with data [" + evt.getData() + "]"); } List<Object> results = new ArrayList<Object>(); Object result; for (ListenerHandler _listener : listeners) { if (log.isDebugEnabled()) { log.debug("Invoking listener [" + _listener.bean.getClass() + '.' + _listener.method.getName() + "(arg)] for event [" + evt.getEvent() + "] with data [" + evt.getData() + "]"); } try { result = _listener.invoke(evt); } catch (Throwable throwable) { result = throwable; } if (result != null) results.add(result); } Object resultValues = null; // Make sure no-result does not cause an error if (results.size() >= 1) { if (results.size() != 1) { resultValues = results; } else { resultValues = results.get(0); } } return new InvokeResult(results.size(), resultValues); } public class InvokeResult { private int invoked; private Object result; public int getInvoked() { return invoked; } public Object getResult() { return result; } public InvokeResult(int invoked, Object result) { this.invoked = invoked; this.result = result; } } private static class ListenerHandler implements EventHandler { private Object bean; private Method method; private ListenerId listenerId; private boolean useEventMessage = false; private boolean noArgs = false; public ListenerHandler(Object bean, Method m, ListenerId listenerId) { this.listenerId = listenerId; method = m; if (m.getParameterTypes().length > 0) { Class<?> type = m.getParameterTypes()[0]; useEventMessage = EventMessage.class.isAssignableFrom(type); if (useEventMessage && log.isDebugEnabled()) { log.debug("Listener " + bean.getClass() + "." + method.getName() + " will receive EventMessage enveloppe"); } } else { noArgs = true; } this.bean = bean; } public Object invoke(EventMessage<?> _arg) throws Throwable { Object res = null; Object arg = isUseEventMessage() ? _arg : _arg.getData(); if (log.isDebugEnabled()) { StringBuilder argTypes = new StringBuilder(); for (Object e : method.getParameterTypes()) { argTypes.append(e.toString()); argTypes.append(','); } log.debug("About to invoke listener method " + bean.getClass() + "." + method.getName() + " with arg type " + argTypes + " with arg " + arg.toString()); } try { if (noArgs) { res = method.invoke(bean); } else { res = method.invoke(bean, arg); } } catch (IllegalArgumentException e) { //ignoring if (log.isDebugEnabled()) { log.debug("Ignoring call to " + bean.getClass() + "." + method.getName() + " with args " + arg.toString() + " - illegal arg exception: " + e.toString()); } } catch (InvocationTargetException e) { log.warn("Failing call to " + bean.getClass() + "." + method.getName() + " with args " + arg.toString() + " - illegal arg invokation " + e.toString(), e.getCause()); throw e.getCause(); } catch (Throwable e) { if (log.isDebugEnabled()) { log.debug("Failing call to " + bean.getClass() + "." + method.getName() + " with args " + arg.toString() + " : " + e.toString()); } throw e; } return res; } public ListenerId getListenerId() { return listenerId; } public boolean isUseEventMessage() { return useEventMessage; } } }