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 }