KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > inject > ProxyFactory


1 /**
2  * Copyright (C) 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package com.google.inject;
18
19 import com.google.inject.util.GuiceFastClass;
20 import com.google.inject.util.GuiceNamingPolicy;
21 import com.google.inject.util.Objects;
22 import com.google.inject.util.ReferenceCache;
23 import java.lang.reflect.Constructor JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import net.sf.cglib.proxy.Callback;
31 import net.sf.cglib.proxy.CallbackFilter;
32 import net.sf.cglib.proxy.Enhancer;
33 import net.sf.cglib.proxy.NoOp;
34 import net.sf.cglib.reflect.FastClass;
35 import net.sf.cglib.reflect.FastConstructor;
36 import org.aopalliance.intercept.MethodInterceptor;
37
38 /**
39  * Proxies classes applying interceptors to methods as specified in
40  * {@link ProxyFactoryBuilder}.
41  *
42  * @author crazybob@google.com (Bob Lee)
43  */

44 class ProxyFactory implements ConstructionProxyFactory {
45
46   final List JavaDoc<MethodAspect> methodAspects;
47   final ConstructionProxyFactory defaultFactory
48       = new DefaultConstructionProxyFactory();
49
50   ProxyFactory(List JavaDoc<MethodAspect> methodAspects) {
51     this.methodAspects = methodAspects;
52   }
53
54   Map JavaDoc<Constructor JavaDoc<?>, ConstructionProxy<?>> constructionProxies
55       = new ReferenceCache<Constructor JavaDoc<?>, ConstructionProxy<?>>() {
56     protected ConstructionProxy<?> create(Constructor JavaDoc<?> constructor) {
57       return createConstructionProxy(constructor);
58     }
59   };
60
61   /**
62    * Gets a factory for the given type. Uses the zero-arg constructor. Wraps
63    * exceptions in {@link RuntimeException} including
64    * {@link InvocationTargetException}.
65    */

66   public <T> Provider<T> getFactory(Class JavaDoc<T> type) throws NoSuchMethodException JavaDoc {
67     final ConstructionProxy<T> constructionProxy
68         = createConstructionProxy(type.getDeclaredConstructor());
69     return new Provider<T>() {
70       public T get() {
71         try {
72           return constructionProxy.newInstance();
73         }
74         catch (InvocationTargetException JavaDoc e) {
75           throw new RuntimeException JavaDoc(e);
76         }
77       }
78     };
79   }
80
81   <T> ConstructionProxy<T> createConstructionProxy(Constructor JavaDoc<T> constructor) {
82     Class JavaDoc<T> declaringClass = constructor.getDeclaringClass();
83
84     // Find applicable aspects. Bow out if none are applicable to this class.
85
List JavaDoc<MethodAspect> applicableAspects = new ArrayList JavaDoc<MethodAspect>();
86     for (MethodAspect methodAspect : methodAspects) {
87       if (methodAspect.matches(declaringClass)) {
88         applicableAspects.add(methodAspect);
89       }
90     }
91     if (applicableAspects.isEmpty()) {
92       return defaultFactory.get(constructor);
93     }
94
95     // Get list of methods from cglib.
96
List JavaDoc<Method JavaDoc> methods = new ArrayList JavaDoc<Method JavaDoc>();
97     Enhancer.getMethods(declaringClass, null, methods);
98     final Map JavaDoc<Method JavaDoc, Integer JavaDoc> indices = new HashMap JavaDoc<Method JavaDoc, Integer JavaDoc>();
99
100     // Create method/interceptor holders and record indices.
101
List JavaDoc<MethodInterceptorsPair> methodInterceptorsPairs
102         = new ArrayList JavaDoc<MethodInterceptorsPair>();
103     for (int i = 0; i < methods.size(); i++) {
104       Method JavaDoc method = methods.get(i);
105       methodInterceptorsPairs.add(new MethodInterceptorsPair(method));
106       indices.put(method, i);
107     }
108
109     // Iterate over aspects and add interceptors for the methods they apply to
110
boolean anyMatched = false;
111     for (MethodAspect methodAspect : applicableAspects) {
112       for (MethodInterceptorsPair pair : methodInterceptorsPairs) {
113         if (methodAspect.matches(pair.method)) {
114           pair.addAll(methodAspect.interceptors());
115           anyMatched = true;
116         }
117       }
118     }
119     if (!anyMatched) {
120       // not test-covered
121
return defaultFactory.get(constructor);
122     }
123
124     // Create callbacks.
125
Callback[] callbacks = new Callback[methods.size()];
126
127     @SuppressWarnings JavaDoc("unchecked")
128     Class JavaDoc<? extends Callback>[] callbackTypes = new Class JavaDoc[methods.size()];
129     for (int i = 0; i < methods.size(); i++) {
130       MethodInterceptorsPair pair = methodInterceptorsPairs.get(i);
131       if (!pair.hasInterceptors()) {
132         callbacks[i] = NoOp.INSTANCE;
133         callbackTypes[i] = NoOp.class;
134       }
135       else {
136         callbacks[i] = new InterceptorStackCallback(
137             pair.method, pair.interceptors);
138         callbackTypes[i] = net.sf.cglib.proxy.MethodInterceptor.class;
139       }
140     }
141
142     // Create the proxied class.
143
Enhancer enhancer = new Enhancer();
144     enhancer.setSuperclass(declaringClass);
145     enhancer.setUseCache(false); // We do enough caching.
146
enhancer.setCallbackFilter(new CallbackFilter() {
147       public int accept(Method JavaDoc method) {
148         return indices.get(method);
149       }
150     });
151     enhancer.setCallbackTypes(callbackTypes);
152     enhancer.setUseFactory(false);
153     enhancer.setNamingPolicy(new GuiceNamingPolicy());
154
155     Class JavaDoc<?> proxied = enhancer.createClass();
156
157     // Store callbacks.
158
Enhancer.registerStaticCallbacks(proxied, callbacks);
159
160     return createConstructionProxy(proxied, constructor.getParameterTypes());
161   }
162
163   /**
164    * Creates a construction proxy given a class and parameter types.
165    */

166   <T> ConstructionProxy<T> createConstructionProxy(Class JavaDoc<?> clazz,
167       Class JavaDoc[] parameterTypes) {
168     FastClass fastClass = GuiceFastClass.create(clazz);
169     final FastConstructor fastConstructor
170         = fastClass.getConstructor(parameterTypes);
171     return new ConstructionProxy<T>() {
172       @SuppressWarnings JavaDoc("unchecked")
173       public T newInstance(Object JavaDoc... arguments)
174           throws InvocationTargetException JavaDoc {
175         Objects.assertNoNulls(arguments);
176         return (T) fastConstructor.newInstance(arguments);
177       }
178     };
179   }
180
181   static class MethodInterceptorsPair {
182
183     final Method JavaDoc method;
184     List JavaDoc<MethodInterceptor> interceptors;
185
186     public MethodInterceptorsPair(Method JavaDoc method) {
187       this.method = method;
188     }
189
190     void addAll(List JavaDoc<MethodInterceptor> interceptors) {
191       if (this.interceptors == null) {
192         this.interceptors = new ArrayList JavaDoc<MethodInterceptor>();
193       }
194       this.interceptors.addAll(interceptors);
195     }
196
197     boolean hasInterceptors() {
198       return interceptors != null;
199     }
200   }
201
202   @SuppressWarnings JavaDoc("unchecked")
203   public <T> ConstructionProxy<T> get(Constructor JavaDoc<T> constructor) {
204     return (ConstructionProxy<T>) constructionProxies.get(constructor);
205   }
206 }
207
Popular Tags