View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  package org.apache.geronimo.kernel.basic;
19  
20  import net.sf.cglib.asm.Type;
21  import net.sf.cglib.core.Signature;
22  import net.sf.cglib.proxy.MethodInterceptor;
23  import net.sf.cglib.proxy.MethodProxy;
24  import net.sf.cglib.reflect.FastClass;
25  import org.apache.geronimo.gbean.AbstractName;
26  import org.apache.geronimo.gbean.GAttributeInfo;
27  import org.apache.geronimo.gbean.GBeanData;
28  import org.apache.geronimo.gbean.GBeanInfo;
29  import org.apache.geronimo.gbean.GOperationInfo;
30  import org.apache.geronimo.gbean.GOperationSignature;
31  import org.apache.geronimo.gbean.runtime.GBeanInstance;
32  import org.apache.geronimo.gbean.runtime.RawInvoker;
33  import org.apache.geronimo.kernel.Kernel;
34  import org.apache.geronimo.kernel.management.State;
35  import org.apache.geronimo.kernel.proxy.DeadProxyException;
36  import org.apache.geronimo.kernel.proxy.GeronimoManagedBean;
37  
38  import java.beans.Introspector;
39  import java.lang.reflect.Method;
40  import java.util.HashSet;
41  import java.util.Iterator;
42  import java.util.Map;
43  import java.util.Set;
44  
45  /**
46   * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
47   */
48  public class ProxyMethodInterceptor implements MethodInterceptor {
49      /**
50       * Type of the proxy interface
51       */
52      private final Class proxyType;
53  
54      /**
55       * The object name to which we are connected.
56       */
57      private final AbstractName abstractName;
58  
59      /**
60       * GBeanInvokers keyed on the proxy interface method index
61       */
62      private ProxyInvoker[] gbeanInvokers;
63  
64      public ProxyMethodInterceptor(Class proxyType, Kernel kernel, AbstractName abstractName) {
65          assert proxyType != null;
66          assert kernel != null;
67          assert abstractName != null;
68  
69          this.proxyType = proxyType;
70          this.abstractName = abstractName;
71          gbeanInvokers = createGBeanInvokers(kernel, abstractName);
72      }
73  
74      public synchronized void destroy() {
75          gbeanInvokers = null;
76      }
77  
78      public AbstractName getAbstractName() {
79          return abstractName;
80      }
81  
82      public final Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
83          ProxyInvoker gbeanInvoker;
84  
85          int interfaceIndex = proxy.getSuperIndex();
86          synchronized (this) {
87              if (gbeanInvokers == null) {
88                  throw new DeadProxyException("Proxy is no longer valid");
89              }
90              gbeanInvoker = gbeanInvokers[interfaceIndex];
91          }
92  
93          if (gbeanInvoker == null) {
94              throw new UnsupportedOperationException("No implementation method: objectName=" + abstractName + ", method=" + method);
95          }
96  
97          return gbeanInvoker.invoke(abstractName, args);
98      }
99  
100     private ProxyInvoker[] createGBeanInvokers(Kernel kernel, AbstractName abstractName) {
101         ProxyInvoker[] invokers;
102         try {
103             RawInvoker rawInvoker = (RawInvoker) kernel.getAttribute(abstractName, GBeanInstance.RAW_INVOKER);
104             invokers = createRawGBeanInvokers(rawInvoker, proxyType);
105         } catch (Exception e) {
106             invokers = createKernelGBeanInvokers(kernel, abstractName, proxyType);
107         }
108 
109         // handle equals, hashCode and toString directly here
110         try {
111             invokers[getSuperIndex(proxyType, proxyType.getMethod("equals", new Class[]{Object.class}))] = new EqualsInvoke(kernel);
112             invokers[getSuperIndex(proxyType, proxyType.getMethod("hashCode", null))] = new HashCodeInvoke();
113             invokers[getSuperIndex(proxyType, proxyType.getMethod("toString", null))] = new ToStringInvoke(proxyType.getName());
114             if(GeronimoManagedBean.class.isAssignableFrom(proxyType)) {
115                 invokers[getSuperIndex(proxyType, proxyType.getMethod("getState", null))] = new GetStateInvoke(kernel);
116                 invokers[getSuperIndex(proxyType, proxyType.getMethod("getStateInstance", null))] = new GetStateInstanceInvoke(kernel);
117                 invokers[getSuperIndex(proxyType, proxyType.getMethod("start", null))] = new StartInvoke(kernel);
118                 invokers[getSuperIndex(proxyType, proxyType.getMethod("startRecursive", null))] = new StartRecursiveInvoke(kernel);
119                 invokers[getSuperIndex(proxyType, proxyType.getMethod("stop", null))] = new StopInvoke(kernel);
120                 invokers[getSuperIndex(proxyType, proxyType.getMethod("getStartTime", null))] = new GetStartTimeInvoke(kernel);
121                 invokers[getSuperIndex(proxyType, proxyType.getMethod("getObjectName", null))] = new GetObjectNameInvoke(kernel);
122             }
123         } catch (Exception e) {
124             // this can not happen... all classes must implement equals, hashCode and toString
125             throw new AssertionError(new Exception("Could not install invoker for proxyType " + proxyType + " for target " + abstractName, e));
126         }
127 
128         return invokers;
129     }
130 
131     private ProxyInvoker[] createRawGBeanInvokers(RawInvoker rawInvoker, Class proxyType) {
132         Map operations = rawInvoker.getOperationIndex();
133         Map attributes = rawInvoker.getAttributeIndex();
134 
135         // build the method lookup table
136         FastClass fastClass = FastClass.create(proxyType);
137         ProxyInvoker[] invokers = new ProxyInvoker[fastClass.getMaxIndex() + 1];
138         Method[] methods = proxyType.getMethods();
139         for (int i = 0; i < methods.length; i++) {
140             Method method = methods[i];
141             int interfaceIndex = getSuperIndex(proxyType, method);
142             if (interfaceIndex >= 0) {
143                 invokers[interfaceIndex] = createRawGBeanInvoker(rawInvoker, method, operations, attributes);
144             }
145         }
146 
147         return invokers;
148     }
149 
150     private ProxyInvoker createRawGBeanInvoker(RawInvoker rawInvoker, Method method, Map operations, Map attributes) {
151         if (operations.containsKey(new GOperationSignature(method))) {
152             int methodIndex = ((Integer) operations.get(new GOperationSignature(method))).intValue();
153             return new RawOperationInvoker(rawInvoker, methodIndex);
154         }
155 
156         if (method.getName().startsWith("get")) {
157             String attributeName = method.getName().substring(3);
158             Integer methodIndex = ((Integer) attributes.get(attributeName));
159             if (methodIndex != null) {
160                 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
161             }
162             methodIndex = getMethodIndex(attributes, attributeName);
163             if (methodIndex != null) {
164                 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
165             }
166         }
167 
168         if (method.getName().startsWith("is")) {
169             String attributeName = method.getName().substring(2);
170             Integer methodIndex = ((Integer) attributes.get(attributeName));
171             if (methodIndex != null) {
172                 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
173             }
174             methodIndex = getMethodIndex(attributes, attributeName);
175             if (methodIndex != null) {
176                 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
177             }
178         }
179 
180         if (method.getName().startsWith("set")) {
181             String attributeName = method.getName().substring(3);
182             Integer methodIndex = ((Integer) attributes.get(attributeName));
183             if (methodIndex != null) {
184                 return new RawSetAttributeInvoker(rawInvoker, methodIndex.intValue());
185             }
186             methodIndex = getMethodIndex(attributes, attributeName);
187             if (methodIndex != null) {
188                 return new RawSetAttributeInvoker(rawInvoker, methodIndex.intValue());
189             }
190         }
191         return null;
192     }
193 
194     private ProxyInvoker[] createKernelGBeanInvokers(Kernel kernel, AbstractName abstractName, Class proxyType) {
195         GBeanInfo info;
196         try {
197             info = kernel.getGBeanInfo(abstractName);
198         } catch (Exception e) {
199             throw new IllegalArgumentException("Could not get GBeanInfo for target object: " + abstractName);
200         }
201 
202         // build attributeName->attributeInfo map
203         Set attributeInfos = info.getAttributes();
204         Set attributeNames = new HashSet(attributeInfos.size());
205         for (Iterator iterator = attributeInfos.iterator(); iterator.hasNext();) {
206             GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
207             attributeNames.add(attributeInfo.getName());
208         }
209 
210         // build operationSignature->operationInfo map
211         Set operationInfos = info.getOperations();
212         Set operationSignatures = new HashSet(operationInfos.size());
213         for (Iterator iterator = operationInfos.iterator(); iterator.hasNext();) {
214             GOperationInfo operationInfo = (GOperationInfo) iterator.next();
215             operationSignatures.add(new GOperationSignature(operationInfo.getName(), operationInfo.getParameterList()));
216         }
217 
218         // build the method lookup table
219         FastClass fastClass = FastClass.create(proxyType);
220         ProxyInvoker[] invokers = new ProxyInvoker[fastClass.getMaxIndex() + 1];
221         Method[] methods = proxyType.getMethods();
222         for (int i = 0; i < methods.length; i++) {
223             Method method = methods[i];
224             int interfaceIndex = getSuperIndex(proxyType, method);
225             if (interfaceIndex >= 0) {
226                 invokers[interfaceIndex] = createJMXGBeanInvoker(kernel, method, operationSignatures, attributeNames);
227             }
228         }
229 
230         return invokers;
231     }
232 
233     private ProxyInvoker createJMXGBeanInvoker(Kernel kernel, Method method, Set operationSignatures, Set attributeNames) {
234         if (operationSignatures.contains(new GOperationSignature(method))) {
235             return new KernelOperationInvoker(kernel, method);
236         }
237 
238         String name = method.getName();
239         if (name.startsWith("get")) {
240             String attributeName = method.getName().substring(3);
241             if (attributeNames.contains(attributeName)) {
242                 return new KernelGetAttributeInvoker(kernel, attributeName);
243             }
244             attributeName = Introspector.decapitalize(attributeName);
245             if (attributeNames.contains(attributeName)) {
246                 return new KernelGetAttributeInvoker(kernel, attributeName);
247             }
248         } else if (name.startsWith("is")) {
249             String attrName = method.getName().substring(2);
250             if (attributeNames.contains(attrName)) {
251                 return new KernelGetAttributeInvoker(kernel, attrName);
252             }
253             attrName = Introspector.decapitalize(attrName);
254             if (attributeNames.contains(attrName)) {
255                 return new KernelGetAttributeInvoker(kernel, attrName);
256             }
257         } else if (name.startsWith("set")) {
258             String attrName = method.getName().substring(3);
259             if (attributeNames.contains(attrName)) {
260                 return new KernelSetAttributeInvoker(kernel, attrName);
261             }
262             attrName = Introspector.decapitalize(attrName);
263             if (attributeNames.contains(attrName)) {
264                 return new KernelSetAttributeInvoker(kernel, attrName);
265             }
266         }
267         return null;
268     }
269 
270     private static int getSuperIndex(Class proxyType, Method method) {
271         Signature signature = new Signature(method.getName(), Type.getReturnType(method), Type.getArgumentTypes(method));
272         MethodProxy methodProxy = MethodProxy.find(proxyType, signature);
273         if (methodProxy != null) {
274             return methodProxy.getSuperIndex();
275         }
276         return -1;
277     }
278 
279     private static Integer getMethodIndex(Map attributes, String attributeName) {
280         Iterator iter = attributes.keySet().iterator();
281         while (iter.hasNext()) {
282             String key = (String) iter.next();
283             if (key.equalsIgnoreCase(attributeName)) {
284                 return (Integer) attributes.get(key);
285             }
286         }
287         return null;
288     }
289 
290     static final class HashCodeInvoke implements ProxyInvoker {
291         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
292             return new Integer(abstractName.hashCode());
293         }
294     }
295 
296     static final class EqualsInvoke implements ProxyInvoker {
297         private final Kernel kernel;
298 
299         public EqualsInvoke(Kernel kernel) {
300             this.kernel = kernel;
301         }
302 
303         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
304             AbstractName proxyTarget = kernel.getAbstractNameFor(arguments[0]);
305             return Boolean.valueOf(abstractName.equals(proxyTarget));
306         }
307     }
308 
309     static final class ToStringInvoke implements ProxyInvoker {
310         private final String interfaceName;
311 
312         public ToStringInvoke(String interfaceName) {
313             this.interfaceName = "[" + interfaceName + ": ";
314         }
315 
316         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
317             return interfaceName + abstractName + "]";
318         }
319     }
320 
321     static final class GetStateInvoke implements ProxyInvoker {
322         private Kernel kernel;
323 
324         public GetStateInvoke(Kernel kernel) {
325             this.kernel = kernel;
326         }
327 
328         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
329             return new Integer(kernel.getGBeanState(abstractName));
330         }
331     }
332 
333     static final class GetStateInstanceInvoke implements ProxyInvoker {
334         private Kernel kernel;
335 
336         public GetStateInstanceInvoke(Kernel kernel) {
337             this.kernel = kernel;
338         }
339 
340         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
341             return State.fromInt(kernel.getGBeanState(abstractName));
342         }
343     }
344 
345     static final class StartInvoke implements ProxyInvoker {
346         private Kernel kernel;
347 
348         public StartInvoke(Kernel kernel) {
349             this.kernel = kernel;
350         }
351 
352         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
353             kernel.startGBean(abstractName);
354             return null;
355         }
356     }
357 
358     static final class StartRecursiveInvoke implements ProxyInvoker {
359         private Kernel kernel;
360 
361         public StartRecursiveInvoke(Kernel kernel) {
362             this.kernel = kernel;
363         }
364 
365         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
366             kernel.startRecursiveGBean(abstractName);
367             return null;
368         }
369     }
370 
371     static final class GetStartTimeInvoke implements ProxyInvoker {
372         private Kernel kernel;
373 
374         public GetStartTimeInvoke(Kernel kernel) {
375             this.kernel = kernel;
376         }
377 
378         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
379             return new Long(kernel.getGBeanStartTime(abstractName));
380         }
381     }
382 
383     static final class StopInvoke implements ProxyInvoker {
384         private Kernel kernel;
385 
386         public StopInvoke(Kernel kernel) {
387             this.kernel = kernel;
388         }
389 
390         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
391             kernel.stopGBean(abstractName);
392             return null;
393         }
394     }
395 
396     static final class GetObjectNameInvoke implements ProxyInvoker {
397         private Kernel kernel;
398 
399         public GetObjectNameInvoke(Kernel kernel) {
400             this.kernel = kernel;
401         }
402 
403         public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
404             GBeanData gBeanData = kernel.getGBeanData(abstractName);
405             return gBeanData.getAbstractName().getObjectName().getCanonicalName();
406         }
407     }
408 }