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
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
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
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
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
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
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 }