001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.geronimo.kernel.basic; 019 020 import net.sf.cglib.asm.Type; 021 import net.sf.cglib.core.Signature; 022 import net.sf.cglib.proxy.MethodInterceptor; 023 import net.sf.cglib.proxy.MethodProxy; 024 import net.sf.cglib.reflect.FastClass; 025 import org.apache.geronimo.gbean.AbstractName; 026 import org.apache.geronimo.gbean.GAttributeInfo; 027 import org.apache.geronimo.gbean.GBeanData; 028 import org.apache.geronimo.gbean.GBeanInfo; 029 import org.apache.geronimo.gbean.GOperationInfo; 030 import org.apache.geronimo.gbean.GOperationSignature; 031 import org.apache.geronimo.gbean.runtime.GBeanInstance; 032 import org.apache.geronimo.gbean.runtime.RawInvoker; 033 import org.apache.geronimo.kernel.Kernel; 034 import org.apache.geronimo.kernel.management.State; 035 import org.apache.geronimo.kernel.proxy.DeadProxyException; 036 import org.apache.geronimo.kernel.proxy.GeronimoManagedBean; 037 038 import java.beans.Introspector; 039 import java.lang.reflect.Method; 040 import java.util.HashSet; 041 import java.util.Iterator; 042 import java.util.Map; 043 import java.util.Set; 044 045 /** 046 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $ 047 */ 048 public class ProxyMethodInterceptor implements MethodInterceptor { 049 /** 050 * Type of the proxy interface 051 */ 052 private final Class proxyType; 053 054 /** 055 * The object name to which we are connected. 056 */ 057 private final AbstractName abstractName; 058 059 /** 060 * GBeanInvokers keyed on the proxy interface method index 061 */ 062 private ProxyInvoker[] gbeanInvokers; 063 064 public ProxyMethodInterceptor(Class proxyType, Kernel kernel, AbstractName abstractName) { 065 assert proxyType != null; 066 assert kernel != null; 067 assert abstractName != null; 068 069 this.proxyType = proxyType; 070 this.abstractName = abstractName; 071 gbeanInvokers = createGBeanInvokers(kernel, abstractName); 072 } 073 074 public synchronized void destroy() { 075 gbeanInvokers = null; 076 } 077 078 public AbstractName getAbstractName() { 079 return abstractName; 080 } 081 082 public final Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable { 083 ProxyInvoker gbeanInvoker; 084 085 int interfaceIndex = proxy.getSuperIndex(); 086 synchronized (this) { 087 if (gbeanInvokers == null) { 088 throw new DeadProxyException("Proxy is no longer valid"); 089 } 090 gbeanInvoker = gbeanInvokers[interfaceIndex]; 091 } 092 093 if (gbeanInvoker == null) { 094 throw new UnsupportedOperationException("No implementation method: objectName=" + abstractName + ", method=" + method); 095 } 096 097 return gbeanInvoker.invoke(abstractName, args); 098 } 099 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 }