View Javadoc
1 /* 2 * Dispatcher.java 3 * Created on August 23, 2003 4 * 5 * The Blues Framework - A lightweight application framework 6 * Copyright (C) 2003 Lonnie Pryor 7 * http://blues.lonniepryor.com 8 * 9 * This library is free software; you can redistribute it and/or modify it under the 10 * terms of the GNU Lesser General Public License as published by the Free Software 11 * Foundation; either version 2.1 of the License, or (at your option) any later 12 * version. 13 * 14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License along 19 * with this library; if not, write to: 20 * 21 * The Free Software Foundation, Inc. 22 * 59 Temple Place, Suite 330 23 * Boston, MA 02111-1307 USA 24 * 25 */ 26 package com.lonniepryor.blues.sys; 27 28 import java.lang.reflect.Member; 29 import java.lang.reflect.Method; 30 31 import java.util.Arrays; 32 import java.util.Collections; 33 import java.util.HashSet; 34 import java.util.LinkedList; 35 import java.util.List; 36 import java.util.Set; 37 38 import com.lonniepryor.blues.Lifecycle; 39 import com.lonniepryor.blues.util.Methods; 40 import com.lonniepryor.blues.util.Types; 41 42 import net.sf.cglib.Enhancer; 43 import net.sf.cglib.MethodFilter; 44 import net.sf.cglib.MethodInterceptor; 45 import net.sf.cglib.MethodProxy; 46 47 /*** 48 * Models the abstract view of a Blues event dispatcher. 49 * 50 * @author Lonnie Pryor 51 * @version $Revision: 1.1 $ 52 */ 53 public final class Dispatcher { 54 /*** 55 * A specification satisfied by interfaces that have only void methods, with the 56 * exception of {@link com.lonniepryor.blues.Lifecycle} and the interfaces in 57 * {@link com.lonniepryor.blues.aop}. 58 */ 59 private static final Types validObserverTypes = Types.interfaces() 60 .and( 61 Types.equalTo(Lifecycle.class).or(Types.named("com.lonniepryor.blues.aop.*")) 62 .not()).and(Types.withAllMethods(Methods.returningVoid())); 63 /*** The observer interface that target components implement. */ 64 private final Class observerType; 65 /*** The target observer instances. */ 66 private final List targetInstances = new LinkedList(); 67 /*** The instance of the dispatcher object. */ 68 private Object instance = null; 69 70 /*** 71 * Creates a new Dispatcher object. 72 * 73 * @param observerInterface The observer interface that target components 74 * implement. 75 */ 76 Dispatcher (Class observerInterface) { 77 if (!validObserverTypes.isSatisfiedBy(observerInterface)) 78 throw new SystemException( 79 "Invalid observer interface " + observerInterface.getName()); 80 this.observerType = observerInterface; 81 } 82 83 /*** 84 * Determines all of the valid observer interfaces implemented by the supplied 85 * component. 86 * 87 * @param comp The component to inspect. 88 * 89 * @return All of the valid observer interfaces implemented by the supplied 90 * component. 91 */ 92 static Class[] observerInterfacesFor (Component comp) { 93 Set observerTypes = indexOberverTypes( 94 comp.getComponentInstance().getClass(), new HashSet()); 95 return (Class[])observerTypes.toArray(new Class[observerTypes.size()]); 96 } 97 98 /*** 99 * Recusivly determines all of the valid observer interfaces implemented by the 100 * supplied class. 101 * 102 * @param onClass The class to inspect. 103 * @param toSet The set to add valid observer interfaces to. 104 * 105 * @return The supplied set. 106 */ 107 private static Set indexOberverTypes (Class onClass, Set toSet) { 108 if (validObserverTypes.isSatisfiedBy(onClass)) 109 if (!toSet.add(onClass)) 110 return toSet; 111 Class[] interfaces = onClass.getInterfaces(); 112 for (int i = 0; i < interfaces.length; ++i) 113 indexOberverTypes(interfaces[i], toSet); 114 if (onClass.getSuperclass() != null) 115 indexOberverTypes(onClass.getSuperclass(), toSet); 116 return toSet; 117 } 118 119 /*** 120 * Adds the target component to this dispatcher. 121 * 122 * @param target The component to add. 123 */ 124 void addTarget (Component target) { 125 if (!observerType.isAssignableFrom(target.getComponentInstance().getClass())) 126 throw new SystemException( 127 "Invalid Component type " 128 + target.getComponentInstance().getClass().getName() 129 + " for Dispatcher type " + observerType.getName()); 130 targetInstances.add(target.getComponentInstance()); 131 } 132 133 /*** 134 * Creates an instance of the observer interface that dispatches to all 135 * registered components. 136 * 137 * @param classLoader The classLoader to define classes on. 138 */ 139 void createInstance (ClassLoader classLoader) { 140 final Set observerMethods = Collections.unmodifiableSet( 141 new HashSet(Arrays.asList(observerType.getMethods()))); 142 try { 143 instance = Enhancer.enhance( 144 Object.class, new Class[] { observerType }, 145 new DispatcherMethodInterceptor(targetInstances.toArray()), classLoader, 146 null, 147 new MethodFilter() { 148 public boolean accept (Member member) { 149 return observerMethods.contains(member); 150 } 151 }); 152 } catch (RuntimeException re) { 153 throw new SystemException( 154 "Error creating Dispatcher for type " + observerType.getName(), re); 155 } 156 } 157 158 /*** 159 * Registers the dispatcher instance with the supplied registry. 160 * 161 * @param reg The registry to register with. 162 */ 163 void registerWith (Registry reg) { 164 reg.registerDispatcher(observerType, instance); 165 } 166 } 167 168 169 /*** 170 * CGLib method interceptor for dispatcher instances. 171 * 172 * @author Lonnie Pryor 173 * @version $Revision: 1.1 $ 174 */ 175 final class DispatcherMethodInterceptor implements MethodInterceptor { 176 /*** The targets registered to recieve events from this dispatcher. */ 177 private final Object[] targets; 178 179 /*** 180 * Creates a new DispatcherMethodInterceptor object. 181 * 182 * @param targets The targets to dispatch events to. 183 */ 184 DispatcherMethodInterceptor (Object[] targets) { 185 this.targets = targets; 186 } 187 188 /* (non-Javadoc) 189 * @see net.sf.cglib.MethodInterceptor#intercept(java.lang.Object, 190 * java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.MethodProxy) 191 */ 192 public Object intercept ( 193 Object target, Method method, Object[] parameters, MethodProxy proxy) 194 throws Throwable { 195 dispatch(parameters, proxy, 0); 196 return null; 197 } 198 199 /*** 200 * Recusivly dispatches the specified event to all registered observers. 201 * 202 * @param parameters The parameters of the invocation. 203 * @param proxy The method proxy to use. 204 * @param index The index in the list to dispatch to. 205 * 206 * @throws Throwable If the underlying observer fails. 207 */ 208 private void dispatch (Object[] parameters, MethodProxy proxy, int index) 209 throws Throwable { 210 if (index >= targets.length) 211 return; 212 try { 213 proxy.invoke(targets[index], parameters); 214 } finally { 215 dispatch(parameters, proxy, index + 1); 216 } 217 } 218 }

This page was automatically generated by Maven