001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. 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 net.sf.cglib.asm.Type;
020 import net.sf.cglib.core.Signature;
021 import net.sf.cglib.proxy.MethodInterceptor;
022 import net.sf.cglib.proxy.MethodProxy;
023 import net.sf.cglib.reflect.FastClass;
024 import org.apache.geronimo.gbean.AbstractName;
025 import org.apache.geronimo.gbean.GAttributeInfo;
026 import org.apache.geronimo.gbean.GBeanData;
027 import org.apache.geronimo.gbean.GBeanInfo;
028 import org.apache.geronimo.gbean.GOperationInfo;
029 import org.apache.geronimo.gbean.GOperationSignature;
030 import org.apache.geronimo.gbean.runtime.GBeanInstance;
031 import org.apache.geronimo.gbean.runtime.RawInvoker;
032 import org.apache.geronimo.kernel.Kernel;
033 import org.apache.geronimo.kernel.management.State;
034 import org.apache.geronimo.kernel.proxy.DeadProxyException;
035 import org.apache.geronimo.kernel.proxy.GeronimoManagedBean;
036
037 import java.beans.Introspector;
038 import java.lang.reflect.Method;
039 import java.util.HashSet;
040 import java.util.Iterator;
041 import java.util.Map;
042 import java.util.Set;
043
044 /**
045 * @version $Rev: 560100 $ $Date: 2007-07-27 01:00:38 -0400 (Fri, 27 Jul 2007) $
046 */
047 public class ProxyMethodInterceptor implements MethodInterceptor {
048 /**
049 * Type of the proxy interface
050 */
051 private final Class proxyType;
052
053 /**
054 * The object name to which we are connected.
055 */
056 private final AbstractName abstractName;
057
058 /**
059 * GBeanInvokers keyed on the proxy interface method index
060 */
061 private ProxyInvoker[] gbeanInvokers;
062
063 public ProxyMethodInterceptor(Class proxyType, Kernel kernel, AbstractName abstractName) {
064 assert proxyType != null;
065 assert kernel != null;
066 assert abstractName != null;
067
068 this.proxyType = proxyType;
069 this.abstractName = abstractName;
070 gbeanInvokers = createGBeanInvokers(kernel, abstractName);
071 }
072
073 public synchronized void destroy() {
074 gbeanInvokers = null;
075 }
076
077 public AbstractName getAbstractName() {
078 return abstractName;
079 }
080
081 public final Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
082 ProxyInvoker gbeanInvoker;
083
084 int interfaceIndex = proxy.getSuperIndex();
085 synchronized (this) {
086 if (gbeanInvokers == null) {
087 throw new DeadProxyException("Proxy is no longer valid to gbean: " + abstractName);
088 }
089 gbeanInvoker = gbeanInvokers[interfaceIndex];
090 }
091
092 if (gbeanInvoker == null) {
093 throw new UnsupportedOperationException("No implementation method: abstractName=" + abstractName + ", method=" + method);
094 }
095
096 return gbeanInvoker.invoke(abstractName, args);
097 }
098
099 private ProxyInvoker[] createGBeanInvokers(Kernel kernel, AbstractName abstractName) {
100 ProxyInvoker[] invokers;
101 try {
102 RawInvoker rawInvoker = (RawInvoker) kernel.getAttribute(abstractName, GBeanInstance.RAW_INVOKER);
103 invokers = createRawGBeanInvokers(rawInvoker, proxyType);
104 } catch (Exception e) {
105 invokers = createKernelGBeanInvokers(kernel, abstractName, proxyType);
106 }
107
108 // handle equals, hashCode and toString directly here
109 try {
110 invokers[getSuperIndex(proxyType, proxyType.getMethod("equals", new Class[]{Object.class}))] = new EqualsInvoke(kernel);
111 invokers[getSuperIndex(proxyType, proxyType.getMethod("hashCode", null))] = new HashCodeInvoke();
112 invokers[getSuperIndex(proxyType, proxyType.getMethod("toString", null))] = new ToStringInvoke(proxyType.getName());
113 if(GeronimoManagedBean.class.isAssignableFrom(proxyType)) {
114 invokers[getSuperIndex(proxyType, proxyType.getMethod("getState", null))] = new GetStateInvoke(kernel);
115 invokers[getSuperIndex(proxyType, proxyType.getMethod("getStateInstance", null))] = new GetStateInstanceInvoke(kernel);
116 invokers[getSuperIndex(proxyType, proxyType.getMethod("start", null))] = new StartInvoke(kernel);
117 invokers[getSuperIndex(proxyType, proxyType.getMethod("startRecursive", null))] = new StartRecursiveInvoke(kernel);
118 invokers[getSuperIndex(proxyType, proxyType.getMethod("stop", null))] = new StopInvoke(kernel);
119 invokers[getSuperIndex(proxyType, proxyType.getMethod("getStartTime", null))] = new GetStartTimeInvoke(kernel);
120 invokers[getSuperIndex(proxyType, proxyType.getMethod("getObjectName", null))] = new GetObjectNameInvoke(kernel);
121 }
122 } catch (Exception e) {
123 // this can not happen... all classes must implement equals, hashCode and toString
124 throw new AssertionError(new Exception("Could not install invoker for proxyType " + proxyType + " for target " + abstractName, e));
125 }
126
127 return invokers;
128 }
129
130 private ProxyInvoker[] createRawGBeanInvokers(RawInvoker rawInvoker, Class proxyType) {
131 Map operations = rawInvoker.getOperationIndex();
132 Map attributes = rawInvoker.getAttributeIndex();
133
134 // build the method lookup table
135 FastClass fastClass = FastClass.create(proxyType);
136 ProxyInvoker[] invokers = new ProxyInvoker[fastClass.getMaxIndex() + 1];
137 Method[] methods = proxyType.getMethods();
138 for (int i = 0; i < methods.length; i++) {
139 Method method = methods[i];
140 int interfaceIndex = getSuperIndex(proxyType, method);
141 if (interfaceIndex >= 0) {
142 invokers[interfaceIndex] = createRawGBeanInvoker(rawInvoker, method, operations, attributes);
143 }
144 }
145
146 return invokers;
147 }
148
149 private ProxyInvoker createRawGBeanInvoker(RawInvoker rawInvoker, Method method, Map operations, Map attributes) {
150 if (operations.containsKey(new GOperationSignature(method))) {
151 int methodIndex = ((Integer) operations.get(new GOperationSignature(method))).intValue();
152 return new RawOperationInvoker(rawInvoker, methodIndex);
153 }
154
155 if (method.getName().startsWith("get")) {
156 String attributeName = method.getName().substring(3);
157 Integer methodIndex = ((Integer) attributes.get(attributeName));
158 if (methodIndex != null) {
159 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
160 }
161 methodIndex = getMethodIndex(attributes, attributeName);
162 if (methodIndex != null) {
163 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
164 }
165 }
166
167 if (method.getName().startsWith("is")) {
168 String attributeName = method.getName().substring(2);
169 Integer methodIndex = ((Integer) attributes.get(attributeName));
170 if (methodIndex != null) {
171 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
172 }
173 methodIndex = getMethodIndex(attributes, attributeName);
174 if (methodIndex != null) {
175 return new RawGetAttributeInvoker(rawInvoker, methodIndex.intValue());
176 }
177 }
178
179 if (method.getName().startsWith("set")) {
180 String attributeName = method.getName().substring(3);
181 Integer methodIndex = ((Integer) attributes.get(attributeName));
182 if (methodIndex != null) {
183 return new RawSetAttributeInvoker(rawInvoker, methodIndex.intValue());
184 }
185 methodIndex = getMethodIndex(attributes, attributeName);
186 if (methodIndex != null) {
187 return new RawSetAttributeInvoker(rawInvoker, methodIndex.intValue());
188 }
189 }
190 return null;
191 }
192
193 private ProxyInvoker[] createKernelGBeanInvokers(Kernel kernel, AbstractName abstractName, Class proxyType) {
194 GBeanInfo info;
195 try {
196 info = kernel.getGBeanInfo(abstractName);
197 } catch (Exception e) {
198 throw new IllegalArgumentException("Could not get GBeanInfo for target object: " + abstractName, e);
199 }
200
201 // build attributeName->attributeInfo map
202 Set attributeInfos = info.getAttributes();
203 Set attributeNames = new HashSet(attributeInfos.size());
204 for (Iterator iterator = attributeInfos.iterator(); iterator.hasNext();) {
205 GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
206 attributeNames.add(attributeInfo.getName());
207 }
208
209 // build operationSignature->operationInfo map
210 Set operationInfos = info.getOperations();
211 Set operationSignatures = new HashSet(operationInfos.size());
212 for (Iterator iterator = operationInfos.iterator(); iterator.hasNext();) {
213 GOperationInfo operationInfo = (GOperationInfo) iterator.next();
214 operationSignatures.add(new GOperationSignature(operationInfo.getName(), operationInfo.getParameterList()));
215 }
216
217 // build the method lookup table
218 FastClass fastClass = FastClass.create(proxyType);
219 ProxyInvoker[] invokers = new ProxyInvoker[fastClass.getMaxIndex() + 1];
220 Method[] methods = proxyType.getMethods();
221 for (int i = 0; i < methods.length; i++) {
222 Method method = methods[i];
223 int interfaceIndex = getSuperIndex(proxyType, method);
224 if (interfaceIndex >= 0) {
225 invokers[interfaceIndex] = createJMXGBeanInvoker(kernel, method, operationSignatures, attributeNames);
226 }
227 }
228
229 return invokers;
230 }
231
232 private ProxyInvoker createJMXGBeanInvoker(Kernel kernel, Method method, Set operationSignatures, Set attributeNames) {
233 if (operationSignatures.contains(new GOperationSignature(method))) {
234 return new KernelOperationInvoker(kernel, method);
235 }
236
237 String name = method.getName();
238 if (name.startsWith("get")) {
239 String attributeName = method.getName().substring(3);
240 if (attributeNames.contains(attributeName)) {
241 return new KernelGetAttributeInvoker(kernel, attributeName);
242 }
243 attributeName = Introspector.decapitalize(attributeName);
244 if (attributeNames.contains(attributeName)) {
245 return new KernelGetAttributeInvoker(kernel, attributeName);
246 }
247 } else if (name.startsWith("is")) {
248 String attrName = method.getName().substring(2);
249 if (attributeNames.contains(attrName)) {
250 return new KernelGetAttributeInvoker(kernel, attrName);
251 }
252 attrName = Introspector.decapitalize(attrName);
253 if (attributeNames.contains(attrName)) {
254 return new KernelGetAttributeInvoker(kernel, attrName);
255 }
256 } else if (name.startsWith("set")) {
257 String attrName = method.getName().substring(3);
258 if (attributeNames.contains(attrName)) {
259 return new KernelSetAttributeInvoker(kernel, attrName);
260 }
261 attrName = Introspector.decapitalize(attrName);
262 if (attributeNames.contains(attrName)) {
263 return new KernelSetAttributeInvoker(kernel, attrName);
264 }
265 }
266 return null;
267 }
268
269 private static int getSuperIndex(Class proxyType, Method method) {
270 Signature signature = new Signature(method.getName(), Type.getReturnType(method), Type.getArgumentTypes(method));
271 MethodProxy methodProxy = MethodProxy.find(proxyType, signature);
272 if (methodProxy != null) {
273 return methodProxy.getSuperIndex();
274 }
275 return -1;
276 }
277
278 private static Integer getMethodIndex(Map attributes, String attributeName) {
279 Iterator iter = attributes.keySet().iterator();
280 while (iter.hasNext()) {
281 String key = (String) iter.next();
282 if (key.equalsIgnoreCase(attributeName)) {
283 return (Integer) attributes.get(key);
284 }
285 }
286 return null;
287 }
288
289 static final class HashCodeInvoke implements ProxyInvoker {
290 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
291 return new Integer(abstractName.hashCode());
292 }
293 }
294
295 static final class EqualsInvoke implements ProxyInvoker {
296 private final Kernel kernel;
297
298 public EqualsInvoke(Kernel kernel) {
299 this.kernel = kernel;
300 }
301
302 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
303 AbstractName proxyTarget = kernel.getAbstractNameFor(arguments[0]);
304 return Boolean.valueOf(abstractName.equals(proxyTarget));
305 }
306 }
307
308 static final class ToStringInvoke implements ProxyInvoker {
309 private final String interfaceName;
310
311 public ToStringInvoke(String interfaceName) {
312 this.interfaceName = "[" + interfaceName + ": ";
313 }
314
315 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
316 return interfaceName + abstractName + "]";
317 }
318 }
319
320 static final class GetStateInvoke implements ProxyInvoker {
321 private Kernel kernel;
322
323 public GetStateInvoke(Kernel kernel) {
324 this.kernel = kernel;
325 }
326
327 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
328 return new Integer(kernel.getGBeanState(abstractName));
329 }
330 }
331
332 static final class GetStateInstanceInvoke implements ProxyInvoker {
333 private Kernel kernel;
334
335 public GetStateInstanceInvoke(Kernel kernel) {
336 this.kernel = kernel;
337 }
338
339 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
340 return State.fromInt(kernel.getGBeanState(abstractName));
341 }
342 }
343
344 static final class StartInvoke implements ProxyInvoker {
345 private Kernel kernel;
346
347 public StartInvoke(Kernel kernel) {
348 this.kernel = kernel;
349 }
350
351 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
352 kernel.startGBean(abstractName);
353 return null;
354 }
355 }
356
357 static final class StartRecursiveInvoke implements ProxyInvoker {
358 private Kernel kernel;
359
360 public StartRecursiveInvoke(Kernel kernel) {
361 this.kernel = kernel;
362 }
363
364 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
365 kernel.startRecursiveGBean(abstractName);
366 return null;
367 }
368 }
369
370 static final class GetStartTimeInvoke implements ProxyInvoker {
371 private Kernel kernel;
372
373 public GetStartTimeInvoke(Kernel kernel) {
374 this.kernel = kernel;
375 }
376
377 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
378 return new Long(kernel.getGBeanStartTime(abstractName));
379 }
380 }
381
382 static final class StopInvoke implements ProxyInvoker {
383 private Kernel kernel;
384
385 public StopInvoke(Kernel kernel) {
386 this.kernel = kernel;
387 }
388
389 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
390 kernel.stopGBean(abstractName);
391 return null;
392 }
393 }
394
395 static final class GetObjectNameInvoke implements ProxyInvoker {
396 private Kernel kernel;
397
398 public GetObjectNameInvoke(Kernel kernel) {
399 this.kernel = kernel;
400 }
401
402 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
403 GBeanData gBeanData = kernel.getGBeanData(abstractName);
404 return gBeanData.getAbstractName().getObjectName().getCanonicalName();
405 }
406 }
407 }