001 /**
002 *
003 * Copyright 2004 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.kernel.basic;
018
019 import java.lang.reflect.InvocationTargetException;
020 import java.util.ArrayList;
021 import java.util.Collections;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.Set;
025
026 import net.sf.cglib.proxy.Callback;
027 import net.sf.cglib.proxy.Enhancer;
028 import net.sf.cglib.proxy.MethodInterceptor;
029 import net.sf.cglib.reflect.FastClass;
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032 import org.apache.geronimo.gbean.AbstractName;
033 import org.apache.geronimo.gbean.GBeanInfo;
034 import org.apache.geronimo.kernel.ClassLoading;
035 import org.apache.geronimo.kernel.GBeanNotFoundException;
036 import org.apache.geronimo.kernel.Kernel;
037 import org.apache.geronimo.kernel.proxy.ProxyCreationException;
038 import org.apache.geronimo.kernel.proxy.ProxyFactory;
039 import org.apache.geronimo.kernel.proxy.ProxyManager;
040
041 /**
042 * Creates proxies that communicate directly with a Kernel located in the same
043 * JVM as the client.
044 *
045 * @version $Rev:386515 $ $Date: 2006-04-24 00:27:37 -0700 (Mon, 24 Apr 2006) $
046 */
047 public class BasicProxyManager implements ProxyManager {
048 private final static String MANAGED_BEAN_NAME = "org.apache.geronimo.kernel.proxy.GeronimoManagedBean";
049 private final static Log log = LogFactory.getLog(BasicProxyManager.class);
050 private final Kernel kernel;
051
052 private final Map interceptors = Collections.synchronizedMap(new BasicProxyMap());
053
054 public BasicProxyManager(Kernel kernel) {
055 this.kernel = kernel;
056 }
057
058 public ProxyFactory createProxyFactory(Class[] types, ClassLoader classLoader) {
059 if (types == null) throw new NullPointerException("type is null");
060 if (types.length == 0) throw new IllegalArgumentException("interface list is empty");
061 if (classLoader == null) throw new NullPointerException("classLoader is null");
062
063 Class managedBean = null;
064 try {
065 managedBean = classLoader.loadClass(MANAGED_BEAN_NAME);
066 } catch (ClassNotFoundException e) {
067 // Can't load GeronimoManagedBean if the incoming type doesn't have a ClassLoader set
068 log.debug("Unable to add GeronimoManagedBean to proxy (specified class loader does not have class)");
069 }
070
071 if(managedBean != null) {
072 Class[] adjusted = new Class[types.length+1];
073 System.arraycopy(types, 0, adjusted, 0, types.length);
074 adjusted[types.length] = managedBean;
075 types = adjusted;
076 }
077
078 return new ManagedProxyFactory(types, classLoader);
079 }
080
081 public Object createProxy(AbstractName target, Class type) {
082 if (target == null) throw new NullPointerException("target is null");
083 if (type == null) throw new NullPointerException("type is null");
084
085 try {
086 // if the type is visible from the target's classloader use it
087 // otherwise use the type's classloader
088 ClassLoader classLoader;
089 try {
090 classLoader = kernel.getClassLoaderFor(target);
091 if (!type.equals(ClassLoading.loadClass(type.getName(), classLoader))) {
092 classLoader = type.getClassLoader();
093 }
094 } catch (Exception ignored) {
095 classLoader = type.getClassLoader();
096 }
097
098 // add any interface exposed by the gbean that is visible from the selected class loader
099 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) { // shrink first -- may reduce from many to one
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) { // Unlikely (as a result of GeronimoManagedBean)
187 enhancer.setSuperclass(type[0]);
188 } else {
189 if(type[0].isInterface()) {
190 enhancer.setSuperclass(Object.class);
191 enhancer.setInterfaces(type);
192 } else { // there's a class and reduceInterfaces put the class in the first spot
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 }