1 /**
2 *
3 * Copyright 2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.geronimo.kernel.basic;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import net.sf.cglib.proxy.Callback;
27 import net.sf.cglib.proxy.Enhancer;
28 import net.sf.cglib.proxy.MethodInterceptor;
29 import net.sf.cglib.reflect.FastClass;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.geronimo.gbean.AbstractName;
33 import org.apache.geronimo.gbean.GBeanInfo;
34 import org.apache.geronimo.kernel.ClassLoading;
35 import org.apache.geronimo.kernel.GBeanNotFoundException;
36 import org.apache.geronimo.kernel.Kernel;
37 import org.apache.geronimo.kernel.proxy.ProxyCreationException;
38 import org.apache.geronimo.kernel.proxy.ProxyFactory;
39 import org.apache.geronimo.kernel.proxy.ProxyManager;
40
41 /**
42 * Creates proxies that communicate directly with a Kernel located in the same
43 * JVM as the client.
44 *
45 * @version $Rev:386515 $ $Date: 2006-04-24 00:27:37 -0700 (Mon, 24 Apr 2006) $
46 */
47 public class BasicProxyManager implements ProxyManager {
48 private final static String MANAGED_BEAN_NAME = "org.apache.geronimo.kernel.proxy.GeronimoManagedBean";
49 private final static Log log = LogFactory.getLog(BasicProxyManager.class);
50 private final Kernel kernel;
51
52 private final Map interceptors = Collections.synchronizedMap(new BasicProxyMap());
53
54 public BasicProxyManager(Kernel kernel) {
55 this.kernel = kernel;
56 }
57
58 public ProxyFactory createProxyFactory(Class[] types, ClassLoader classLoader) {
59 if (types == null) throw new NullPointerException("type is null");
60 if (types.length == 0) throw new IllegalArgumentException("interface list is empty");
61 if (classLoader == null) throw new NullPointerException("classLoader is null");
62
63 Class managedBean = null;
64 try {
65 managedBean = classLoader.loadClass(MANAGED_BEAN_NAME);
66 } catch (ClassNotFoundException e) {
67
68 log.debug("Unable to add GeronimoManagedBean to proxy (specified class loader does not have class)");
69 }
70
71 if(managedBean != null) {
72 Class[] adjusted = new Class[types.length+1];
73 System.arraycopy(types, 0, adjusted, 0, types.length);
74 adjusted[types.length] = managedBean;
75 types = adjusted;
76 }
77
78 return new ManagedProxyFactory(types, classLoader);
79 }
80
81 public Object createProxy(AbstractName target, Class type) {
82 if (target == null) throw new NullPointerException("target is null");
83 if (type == null) throw new NullPointerException("type is null");
84
85 try {
86
87
88 ClassLoader classLoader;
89 try {
90 classLoader = kernel.getClassLoaderFor(target);
91 if (!type.equals(ClassLoading.loadClass(type.getName(), classLoader))) {
92 classLoader = type.getClassLoader();
93 }
94 } catch (Exception ignored) {
95 classLoader = type.getClassLoader();
96 }
97
98
99 List types = getVisibleInterfaces(target, classLoader, true);
100 if (types == null) types = new ArrayList();
101 types.add(type);
102
103 return createProxyFactory((Class[]) types.toArray(new Class[types.size()]), classLoader).createProxy(target);
104 } catch (GBeanNotFoundException e) {
105 throw new IllegalArgumentException("Could not get GBeanInfo for target object: " + target);
106 }
107 }
108
109 public Object createProxy(AbstractName target, ClassLoader classLoader) {
110 if (target == null) throw new NullPointerException("target is null");
111 if (classLoader == null) throw new NullPointerException("classLoader is null");
112
113 try {
114 List types = getVisibleInterfaces(target, classLoader, true);
115 if (types == null) return null;
116 return createProxyFactory((Class[]) types.toArray(new Class[types.size()]), classLoader).createProxy(target);
117 } catch (GBeanNotFoundException e) {
118 throw new IllegalArgumentException("Could not get GBeanInfo for target object: " + target);
119 }
120 }
121
122 private List getVisibleInterfaces(AbstractName target, ClassLoader classLoader, boolean shouldLog) throws GBeanNotFoundException {
123 GBeanInfo info = kernel.getGBeanInfo(target);
124 Set interfaces = info.getInterfaces();
125 if(interfaces.size() == 0) {
126 if (shouldLog) {
127 log.warn("No interfaces found for " + target + " ("+target+")");
128 }
129 return null;
130 }
131 String[] names = (String[]) interfaces.toArray(new String[0]);
132 List types = new ArrayList();
133 for (int i = 0; i < names.length; i++) {
134 try {
135 Class type = classLoader.loadClass(names[i]);
136 if (type.isInterface()) {
137 types.add(type);
138 }
139 } catch (ClassNotFoundException e) {
140 if (shouldLog) {
141 log.warn("Could not load interface "+names[i]+" in provided ClassLoader for "+target);
142 }
143 }
144 }
145 return types;
146 }
147
148 public void destroyProxy(Object proxy) {
149 if (proxy == null) {
150 return;
151 }
152
153 MethodInterceptor methodInterceptor = (MethodInterceptor) interceptors.remove(proxy);
154 if (methodInterceptor != null) {
155 doDestroy(methodInterceptor);
156 }
157 }
158
159 public boolean isProxy(Object proxy) {
160 return interceptors.containsKey(proxy);
161 }
162
163 public AbstractName getProxyTarget(Object proxy) {
164 MethodInterceptor methodInterceptor = (MethodInterceptor) interceptors.get(proxy);
165 if (methodInterceptor == null) {
166 return null;
167 }
168 return getAbstractName(methodInterceptor);
169 }
170
171 private class ManagedProxyFactory implements ProxyFactory {
172 private final Class proxyType;
173 private final FastClass fastClass;
174
175 public ManagedProxyFactory(Class type, ClassLoader classLoader) {
176 this(new Class[]{type}, classLoader);
177 }
178
179 public ManagedProxyFactory(Class[] type, ClassLoader classLoader) {
180 Enhancer enhancer = new Enhancer();
181 if(type.length > 1) {
182 type = ClassLoading.reduceInterfaces(type);
183 }
184 if(type.length == 0) {
185 throw new IllegalArgumentException("Cannot generate proxy for 0 interfaces!");
186 } else if(type.length == 1) {
187 enhancer.setSuperclass(type[0]);
188 } else {
189 if(type[0].isInterface()) {
190 enhancer.setSuperclass(Object.class);
191 enhancer.setInterfaces(type);
192 } else {
193 Class[] intfs = new Class[type.length-1];
194 System.arraycopy(type, 1, intfs, 0, intfs.length);
195 enhancer.setSuperclass(type[0]);
196 enhancer.setInterfaces(intfs);
197 }
198 }
199 enhancer.setClassLoader(classLoader);
200 enhancer.setCallbackType(MethodInterceptor.class);
201 enhancer.setUseFactory(false);
202 proxyType = enhancer.createClass();
203 fastClass = FastClass.create(proxyType);
204 }
205
206 public Object createProxy(AbstractName target) {
207 assert target != null: "target is null";
208
209 Callback callback = getMethodInterceptor(proxyType, kernel, target);
210
211 Enhancer.registerCallbacks(proxyType, new Callback[]{callback});
212 try {
213 Object proxy = fastClass.newInstance();
214 interceptors.put(proxy, callback);
215 return proxy;
216 } catch (InvocationTargetException e) {
217 Throwable cause = e.getCause();
218 if (cause instanceof RuntimeException) {
219 throw (RuntimeException) cause;
220 } else if (cause instanceof Error) {
221 throw (Error) cause;
222 } else if (cause != null) {
223 throw new ProxyCreationException(cause);
224 } else {
225 throw new ProxyCreationException(e);
226 }
227 }
228 }
229 }
230
231 protected Callback getMethodInterceptor(Class proxyType, Kernel kernel, AbstractName target) {
232 return new ProxyMethodInterceptor(proxyType, kernel, target);
233 }
234
235 protected void doDestroy(MethodInterceptor methodInterceptor) {
236 ((ProxyMethodInterceptor)methodInterceptor).destroy();
237 }
238
239 protected AbstractName getAbstractName(MethodInterceptor methodInterceptor) {
240 return ((ProxyMethodInterceptor)methodInterceptor).getAbstractName();
241 }
242 }