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: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 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 }