KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > soto > aop > Adviser


1 package org.sapia.soto.aop;
2
3 import net.sf.cglib.proxy.Enhancer;
4 import net.sf.cglib.proxy.Factory;
5
6 import org.sapia.soto.ConfigurationException;
7 import org.sapia.soto.ServiceMetaData;
8 import org.sapia.soto.util.Utils;
9 import org.sapia.soto.util.matcher.PathPattern;
10 import org.sapia.soto.util.matcher.Pattern;
11
12 import java.lang.reflect.Method JavaDoc;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
18
19
20 /**
21  * This class implements provides behavior to "advise" objects dynamically.
22  *
23  * @author Yanick Duchesne
24  * <dl>
25  * <dt><b>Copyright:</b><dd>Copyright &#169; 2002-2003 <a HREF="http://www.sapia-oss.org">Sapia Open Source Software</a>. All Rights Reserved.</dd></dt>
26  * <dt><b>License:</b><dd>Read the license.txt file of the jar or visit the
27  * <a HREF="http://www.sapia-oss.org/license.html">license page</a> at the Sapia OSS web site</dd></dt>
28  * </dl>
29  */

30 public class Adviser {
31   private List JavaDoc _methods = new ArrayList JavaDoc();
32   private List JavaDoc _adviceDefs = new ArrayList JavaDoc();
33   private List JavaDoc _groups = new ArrayList JavaDoc();
34   private Pattern[] _interfaces;
35
36   /**
37    * Constructor for AopLayer.
38    */

39   public Adviser() {
40     super();
41   }
42
43   /**
44    * @see org.sapia.soto.Layer#init(ServiceMetaData)
45    */

46   public void init(ServiceMetaData meta) throws Exception JavaDoc {
47     Object JavaDoc proxy = advise(meta.getService());
48     meta.setService(proxy);
49   }
50
51   /**
52    * Advises the given object and returns a proxy for it.
53    *
54    * @param toAdvise
55    * @return a proxy for the given object.
56    * @throws Exception
57    */

58   public Object JavaDoc advise(Object JavaDoc toAdvise) throws Exception JavaDoc {
59     if (!matchesImplements(toAdvise)) {
60       return toAdvise;
61     }
62
63     MethodPointCut pc;
64     List JavaDoc methods;
65     List JavaDoc adviceRefs;
66     List JavaDoc groupRefs;
67     List JavaDoc advices;
68     AdviceRef ref;
69     GroupRef groupRef;
70
71     Map JavaDoc defs = filterDefs();
72     Map JavaDoc groups = filterGroups(defs);
73     AdviceInterceptor interceptor;
74     boolean advised;
75
76     if (advised = isAdvised(toAdvise)) {
77       interceptor = getInterceptor(toAdvise);
78     } else {
79       interceptor = new AdviceInterceptor(toAdvise.getClass());
80     }
81
82     Method JavaDoc meth;
83
84     for (int i = 0; i < _methods.size(); i++) {
85       pc = (MethodPointCut) _methods.get(i);
86       adviceRefs = pc.getAdviceRefs();
87       groupRefs = pc.getGroupRefs();
88       advices = new ArrayList JavaDoc(adviceRefs.size());
89       methods = pc.scanMethods(toAdvise.getClass());
90
91       for (int j = 0; j < groupRefs.size(); j++) {
92         groupRef = (GroupRef) groupRefs.get(j);
93
94         List JavaDoc resolved = groupRef.resolve(groups);
95         advices.addAll(resolved);
96       }
97
98       for (int j = 0; j < adviceRefs.size(); j++) {
99         ref = (AdviceRef) adviceRefs.get(j);
100         advices.add(ref.resolve(defs));
101       }
102
103       for (int j = 0; j < methods.size(); j++) {
104         Invoker delegate = new Invoker(advices);
105         meth = (Method JavaDoc) methods.get(j);
106
107         if (Factory.class.isAssignableFrom(meth.getDeclaringClass())) {
108           meth = interceptor.getAdvisedClass().getDeclaredMethod(meth.getName(),
109               meth.getParameterTypes());
110         }
111
112         interceptor.addInvoker(meth, delegate);
113       }
114
115       advices.clear();
116     }
117
118     Object JavaDoc proxy;
119
120     if (advised) {
121       proxy = toAdvise;
122     } else {
123       proxy = Enhancer.create(toAdvise.getClass(), Utils.getClasses(toAdvise),
124           interceptor);
125       Utils.copyFields(toAdvise, proxy);
126     }
127
128     return proxy;
129   }
130
131   /**
132    * Clears this instance's state - will have to be reinitialized
133    * in order to be reused.
134    */

135   public void clear() {
136     // Freeing memory - being zealous about it...
137
_adviceDefs.clear();
138     _adviceDefs = null;
139     _groups.clear();
140     _groups = null;
141     _methods.clear();
142     _methods = null;
143   }
144
145   /**
146    * Allows to pass a comma-delimited list of interfaces names (or, rather name patterns)
147    * that an object passed to this instance must implement in order to be advised.
148    *
149    * @param interfaces a comma-delimited list of interfaces.
150    */

151   public void setImplements(String JavaDoc interfaces) {
152     String JavaDoc[] interfacePatterns = Utils.split(interfaces, ',', true);
153     _interfaces = new Pattern[interfacePatterns.length];
154
155     for (int i = 0; i < interfacePatterns.length; i++) {
156       _interfaces[i] = PathPattern.parse(interfacePatterns[i], '.', false);
157     }
158   }
159
160   /**
161    * Return true if the given object implements the interfaces specified to this
162    * instance. If no interfaces were specified, this method returns true all the time.
163    * @param o an <code>Object</code>.
164    * @return <code>true</code> if the given object implements the interfaces specified
165    * to this instance, or if this instance was not specified any interface.
166    *
167    * @see #setImplements(String)
168    */

169   public boolean matchesImplements(Object JavaDoc o) {
170     if (_interfaces == null) {
171       return true;
172     }
173
174     Class JavaDoc[] interfaces = Utils.getClasses(o);
175     boolean[] matched = new boolean[_interfaces.length];
176     Pattern pattern;
177
178     for (int i = 0; i < interfaces.length; i++) {
179       for (int j = 0; j < _interfaces.length; j++) {
180         pattern = (Pattern) _interfaces[j];
181
182         if (pattern.matches(interfaces[i].getName())) {
183           matched[j] = true;
184         }
185       }
186     }
187
188     for (int i = 0; i < matched.length; i++) {
189       if (!matched[i]) {
190         return false;
191       }
192     }
193
194     return true;
195   }
196
197   /**
198    * Creates a method pointcut.
199    *
200    * @return a <code>MethodPointCut</code>.
201    */

202   public MethodPointCut createMethod() {
203     MethodPointCut pc = new MethodPointCut();
204     _methods.add(pc);
205
206     return pc;
207   }
208
209   /**
210    * Creates an advice definition.
211    *
212    * @return an <code>AdviceDef</code> instance.
213    */

214   public AdviceDef createAdviceDef() {
215     AdviceDef def = new AdviceDef();
216     _adviceDefs.add(def);
217
218     return def;
219   }
220
221   /**
222    * Creates a group and returns it.
223    *
224    * @return a <code>Group</code>.
225    */

226   public Group createGroup() {
227     Group g = new Group();
228     _groups.add(g);
229
230     return g;
231   }
232
233   /**
234    * Returns true if the given object is "advised": i.e., if it is a proxy that
235    * encapsulates advices.
236    *
237    * @param obj
238    * @return true if the given object is "advised": i.e., if it is a proxy that
239    * encapsulates advices.
240    */

241   public static boolean isAdvised(Object JavaDoc obj) {
242     try {
243       AdviceInterceptor interceptor = (AdviceInterceptor) ((Factory) obj).getCallback(0);
244
245       return true;
246     } catch (ClassCastException JavaDoc e) {
247       return false;
248     }
249   }
250
251   /**
252    * Returns the advice interceptor that is encapsulated within the given object, which
253    * is a proxy.
254    *
255    * @param obj
256    * @return an <code>AdviceInterceptor</code>, or <code>null</code> if
257    * the given object is not an "advised" object.
258    */

259   public static AdviceInterceptor getInterceptor(Object JavaDoc obj) {
260     try {
261       return (AdviceInterceptor) ((Factory) obj).getCallback(0);
262     } catch (ClassCastException JavaDoc e) {
263       return null;
264     }
265   }
266
267   private Map JavaDoc filterDefs() throws ConfigurationException {
268     Map JavaDoc defs = new HashMap JavaDoc();
269     AdviceDef def;
270
271     for (int i = 0; i < _adviceDefs.size(); i++) {
272       def = (AdviceDef) _adviceDefs.get(i);
273
274       if (def.getId() == null) {
275         throw new ConfigurationException(
276           "'id' attribute not specified on advice definition");
277       }
278
279       defs.put(def.getId(), def);
280     }
281
282     return defs;
283   }
284
285   private Map JavaDoc filterGroups(Map JavaDoc defs) throws ConfigurationException {
286     Map JavaDoc groups = new HashMap JavaDoc();
287     Group group;
288
289     for (int i = 0; i < _groups.size(); i++) {
290       group = (Group) _groups.get(i);
291
292       if (group.getId() == null) {
293         throw new ConfigurationException(
294           "'id' attribute not specified on advice definition");
295       }
296
297       group.resolve(defs);
298
299       groups.put(group.getId(), group);
300     }
301
302     return groups;
303   }
304 }
305
Popular Tags