View Javadoc

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              // Can't load GeronimoManagedBean if the incoming type doesn't have a ClassLoader set
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              // if the type is visible from the target's classloader use it
87              // otherwise use the type's classloader
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              // add any interface exposed by the gbean that is visible from the selected class loader
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) { // 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 }