001/* Copyright 2011-2012 the original author or authors: 002 * 003 * Marc Palmer (marc@grailsrocks.com) 004 * Stéphane Maldini (smaldini@vmware.com) 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.grails.plugin.platform.events.registry; 019 020import groovy.lang.Closure; 021import org.apache.log4j.Logger; 022import org.grails.plugin.platform.events.EventMessage; 023import org.grails.plugin.platform.events.ListenerId; 024import org.springframework.aop.framework.Advised; 025import org.springframework.util.ReflectionUtils; 026 027import java.lang.reflect.InvocationTargetException; 028import java.lang.reflect.Method; 029import java.util.ArrayList; 030import java.util.HashSet; 031import java.util.List; 032import java.util.Set; 033 034/** 035 * @author Stephane Maldini <smaldini@vmware.com> 036 * @version 1.0 037 * @file 038 * @date 02/01/12 039 * @section DESCRIPTION 040 * <p/> 041 * [Does stuff] 042 */ 043public class DefaultEventsRegistry implements EventsRegistry { 044 045 static final private Logger log = Logger.getLogger(DefaultEventsRegistry.class); 046 047 private Set<ListenerHandler> listeners = new HashSet<ListenerHandler>(); 048 049 /* 050 API 051 */ 052 053 public String on(String namespace, String topic, Closure callback) { 054 return registerHandler(callback, namespace, topic); 055 } 056 057 public String on(String namespace, String topic, Object bean, String callbackName) { 058 return registerHandler(bean, ReflectionUtils.findMethod(bean.getClass(), callbackName), namespace, topic); 059 } 060 061 public String on(String namespace, String topic, Object bean, Method callback) { 062 return registerHandler(bean, callback, namespace, topic); 063 } 064 065 public int removeListeners(String callbackId) { 066 ListenerId listener = ListenerId.parse(callbackId); 067 if (listener == null) 068 return 0; 069 synchronized (listeners) { 070 Set<ListenerHandler> listeners = findAll(listener); 071 for (ListenerHandler _listener : listeners) { 072 this.listeners.remove(_listener); 073 } 074 } 075 076 return listeners.size(); 077 } 078 079 public int countListeners(String callbackId) { 080 ListenerId listener = ListenerId.parse(callbackId); 081 if (listener == null) 082 return 0; 083 084 return findAll(listener).size(); 085 } 086 087 /* 088 INTERNAL 089 */ 090 091 private String registerHandler(Closure callback, String namespace, String topic) { 092 if (log.isDebugEnabled()) { 093 log.debug("Registering event handler [" + callback.getClass() + "] for topic [" + topic + "]"); 094 } 095 096 ListenerId listener = ListenerId.build(namespace, topic, callback); 097 ListenerHandler handler = new ListenerHandler(callback, ReflectionUtils.findMethod( 098 callback.getClass(), 099 "call", 100 Object.class 101 ), listener); 102 103 synchronized (listeners) { 104 listeners.add(handler); 105 } 106 107 return listener.toString(); 108 } 109 110 private String registerHandler(Object bean, Method callback, String namespace, String topic) { 111 if (log.isDebugEnabled()) { 112 log.debug("Registering event handler on bean [" + bean + "] method [" + callback + "] for topic [" + topic + "]"); 113 } 114 115 ListenerId listener = ListenerId.build(namespace, topic, bean, callback); 116 117 ListenerHandler handler = new ListenerHandler(bean, callback, listener); 118 119 synchronized (listeners) { 120 listeners.add(handler); 121 } 122 123 return listener.toString(); 124 } 125 126 private Set<ListenerHandler> findAll(ListenerId listener) { 127 if (log.isDebugEnabled()) { 128 log.debug("Finding listeners matching listener id [" + listener.toString() + "]"); 129 } 130 Set<ListenerHandler> listeners = 131 new HashSet<ListenerHandler>(); 132 133 for (ListenerHandler _listener : this.listeners) { 134 if (listener.matches(_listener.getListenerId())) { 135 listeners.add(_listener); 136 } 137 } 138 139 return listeners; 140 } 141 142 public InvokeResult invokeListeners(EventMessage evt) { 143 if (log.isDebugEnabled()) { 144 log.debug("Invoking listeners for event [" + evt.getEvent() + "] namespaced on [" + evt.getNamespace() + "] with data [" + evt.getData() + "]"); 145 } 146 ListenerId listener = new ListenerId(evt.getNamespace(), evt.getEvent()); 147 Set<ListenerHandler> listeners = findAll(listener); 148 149 if (log.isDebugEnabled()) { 150 log.debug("Found " + listeners.size() + " listeners for event [" + evt.getEvent() + "] with data [" + evt.getData() + "]"); 151 } 152 List<Object> results = new ArrayList<Object>(); 153 Object result; 154 for (ListenerHandler _listener : listeners) { 155 if (log.isDebugEnabled()) { 156 log.debug("Invoking listener [" + _listener.bean.getClass() + '.' + _listener.method.getName() + "(arg)] for event [" + evt.getEvent() + "] with data [" + evt.getData() + "]"); 157 } 158 try { 159 result = _listener.invoke(evt); 160 } catch (Throwable throwable) { 161 result = throwable; 162 } 163 if (result != null) results.add(result); 164 } 165 166 Object resultValues = null; 167 // Make sure no-result does not cause an error 168 if (results.size() >= 1) { 169 if (results.size() != 1) { 170 resultValues = results; 171 } else { 172 resultValues = results.get(0); 173 } 174 } 175 return new InvokeResult(results.size(), resultValues); 176 } 177 178 public class InvokeResult { 179 private int invoked; 180 private Object result; 181 182 public int getInvoked() { 183 return invoked; 184 } 185 186 public Object getResult() { 187 return result; 188 } 189 190 public InvokeResult(int invoked, Object result) { 191 this.invoked = invoked; 192 this.result = result; 193 } 194 } 195 196 private static class ListenerHandler implements EventHandler { 197 private Object bean; 198 private Method method; 199 private ListenerId listenerId; 200 private boolean useEventMessage = false; 201 private boolean noArgs = false; 202 203 public ListenerHandler(Object bean, Method m, ListenerId listenerId) { 204 this.listenerId = listenerId; 205 this.method = m; 206 207 if (m.getParameterTypes().length > 0) { 208 Class type = m.getParameterTypes()[0]; 209 useEventMessage = EventMessage.class.isAssignableFrom(type); 210 if (useEventMessage && log.isDebugEnabled()) { 211 log.debug("Listener " + bean.getClass() + "." + method.getName() + " will receive EventMessage enveloppe"); 212 } 213 } else { 214 noArgs = true; 215 } 216 this.bean = bean; 217 //this.mapping = mapping; 218 } 219 220 public Object invoke(EventMessage _arg) throws Throwable { 221 Object res = null; 222 223 Object arg = this.isUseEventMessage() ? _arg : _arg.getData(); 224 225 if (log.isDebugEnabled()) { 226 StringBuilder argTypes = new StringBuilder(); 227 for (Object e : method.getParameterTypes()) { 228 argTypes.append(e.toString()); 229 argTypes.append(','); 230 } 231 log.debug("About to invoke listener method " + bean.getClass() + "." + method.getName() + " with arg type " + argTypes + 232 " with arg " + arg.toString()); 233 } 234 try { 235 if (noArgs) { 236 res = method.invoke(bean); 237 } else { 238 res = method.invoke(bean, arg); 239 } 240 } catch (IllegalArgumentException e) { 241 //ignoring 242 if (log.isDebugEnabled()) { 243 log.debug("Ignoring call to " + bean.getClass() + "." + method.getName() + " with args " + arg.toString() + " - illegal arg exception: " + e.toString()); 244 } 245 } catch (Throwable e) { 246 if (log.isDebugEnabled()) { 247 log.debug("Failing call to " + bean.getClass() + "." + method.getName() + " with args " + arg.toString() + " : " + e.toString()); 248 } 249 throw e; 250 } 251 252 return res; 253 } 254 255 public ListenerId getListenerId() { 256 return listenerId; 257 } 258 259 public boolean isUseEventMessage() { 260 return useEventMessage; 261 } 262 } 263 264 265}