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