Showing the changes to java/pkg/javax/management/MBeanServerInvocationHandler.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,497 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||
| 7 | * published by the Free Software Foundation. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package javax.management; | ||
| 27 | |||
| 28 | import com.sun.jmx.mbeanserver.MXBeanProxy; | ||
| 29 | |||
| 30 | import java.lang.ref.WeakReference; | ||
| 31 | import java.lang.reflect.InvocationHandler; | ||
| 32 | import java.lang.reflect.Method; | ||
| 33 | import java.lang.reflect.Proxy; | ||
| 34 | import java.util.Arrays; | ||
| 35 | import java.util.WeakHashMap; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * <p>{@link InvocationHandler} that forwards methods in an MBean's | ||
| 39 | * management interface through the MBean server to the MBean.</p> | ||
| 40 | * | ||
| 41 | * <p>Given an {@link MBeanServerConnection}, the {@link ObjectName} | ||
| 42 | * of an MBean within that MBean server, and a Java interface | ||
| 43 | * <code>Intf</code> that describes the management interface of the | ||
| 44 | * MBean using the patterns for a Standard MBean or an MXBean, this | ||
| 45 | * class can be used to construct a proxy for the MBean. The proxy | ||
| 46 | * implements the interface <code>Intf</code> such that all of its | ||
| 47 | * methods are forwarded through the MBean server to the MBean.</p> | ||
| 48 | * | ||
| 49 | * <p>If the {@code InvocationHandler} is for an MXBean, then the parameters of | ||
| 50 | * a method are converted from the type declared in the MXBean | ||
| 51 | * interface into the corresponding mapped type, and the return value | ||
| 52 | * is converted from the mapped type into the declared type. For | ||
| 53 | * example, with the method<br> | ||
| 54 | |||
| 55 | * {@code public List<String> reverse(List<String> list);}<br> | ||
| 56 | |||
| 57 | * and given that the mapped type for {@code List<String>} is {@code | ||
| 58 | * String[]}, a call to {@code proxy.reverse(someList)} will convert | ||
| 59 | * {@code someList} from a {@code List<String>} to a {@code String[]}, | ||
| 60 | * call the MBean operation {@code reverse}, then convert the returned | ||
| 61 | * {@code String[]} into a {@code List<String>}.</p> | ||
| 62 | * | ||
| 63 | * <p>The method Object.toString(), Object.hashCode(), or | ||
| 64 | * Object.equals(Object), when invoked on a proxy using this | ||
| 65 | * invocation handler, is forwarded to the MBean server as a method on | ||
| 66 | * the proxied MBean only if it appears in one of the proxy's | ||
| 67 | * interfaces. For a proxy created with {@link | ||
| 68 | * JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class) | ||
| 69 | * JMX.newMBeanProxy} or {@link | ||
| 70 | * JMX#newMXBeanProxy(MBeanServerConnection, ObjectName, Class) | ||
| 71 | * JMX.newMXBeanProxy}, this means that the method must appear in the | ||
| 72 | * Standard MBean or MXBean interface. Otherwise these methods have | ||
| 73 | * the following behavior: | ||
| 74 | * <ul> | ||
| 75 | * <li>toString() returns a string representation of the proxy | ||
| 76 | * <li>hashCode() returns a hash code for the proxy such | ||
| 77 | * that two equal proxies have the same hash code | ||
| 78 | * <li>equals(Object) | ||
| 79 | * returns true if and only if the Object argument is of the same | ||
| 80 | * proxy class as this proxy, with an MBeanServerInvocationHandler | ||
| 81 | * that has the same MBeanServerConnection and ObjectName; if one | ||
| 82 | * of the {@code MBeanServerInvocationHandler}s was constructed with | ||
| 83 | * a {@code Class} argument then the other must have been constructed | ||
| 84 | * with the same {@code Class} for {@code equals} to return true. | ||
| 85 | * </ul> | ||
| 86 | * | ||
| 87 | * @since 1.5 | ||
| 88 | */ | ||
| 89 | public class MBeanServerInvocationHandler implements InvocationHandler { | ||
| 90 | /** | ||
| 91 | * <p>Invocation handler that forwards methods through an MBean | ||
| 92 | * server to a Standard MBean. This constructor may be called | ||
| 93 | * instead of relying on {@link | ||
| 94 | * JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class) | ||
| 95 | * JMX.newMBeanProxy}, for instance if you need to supply a | ||
| 96 | * different {@link ClassLoader} to {@link Proxy#newProxyInstance | ||
| 97 | * Proxy.newProxyInstance}.</p> | ||
| 98 | * | ||
| 99 | * <p>This constructor is not appropriate for an MXBean. Use | ||
| 100 | * {@link #MBeanServerInvocationHandler(MBeanServerConnection, | ||
| 101 | * ObjectName, boolean)} for that. This constructor is equivalent | ||
| 102 | * to {@code new MBeanServerInvocationHandler(connection, | ||
| 103 | * objectName, false)}.</p> | ||
| 104 | * | ||
| 105 | * @param connection the MBean server connection through which all | ||
| 106 | * methods of a proxy using this handler will be forwarded. | ||
| 107 | * | ||
| 108 | * @param objectName the name of the MBean within the MBean server | ||
| 109 | * to which methods will be forwarded. | ||
| 110 | */ | ||
| 111 | public MBeanServerInvocationHandler(MBeanServerConnection connection, | ||
| 112 | ObjectName objectName) { | ||
| 113 | |||
| 114 | this(connection, objectName, false); | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * <p>Invocation handler that can forward methods through an MBean | ||
| 119 | * server to a Standard MBean or MXBean. This constructor may be called | ||
| 120 | * instead of relying on {@link | ||
| 121 | * JMX#newMXBeanProxy(MBeanServerConnection, ObjectName, Class) | ||
| 122 | * JMX.newMXBeanProxy}, for instance if you need to supply a | ||
| 123 | * different {@link ClassLoader} to {@link Proxy#newProxyInstance | ||
| 124 | * Proxy.newProxyInstance}.</p> | ||
| 125 | * | ||
| 126 | * @param connection the MBean server connection through which all | ||
| 127 | * methods of a proxy using this handler will be forwarded. | ||
| 128 | * | ||
| 129 | * @param objectName the name of the MBean within the MBean server | ||
| 130 | * to which methods will be forwarded. | ||
| 131 | * | ||
| 132 | * @param isMXBean if true, the proxy is for an {@link MXBean}, and | ||
| 133 | * appropriate mappings will be applied to method parameters and return | ||
| 134 | * values. | ||
| 135 | * | ||
| 136 | * @since 1.6 | ||
| 137 | */ | ||
| 138 | public MBeanServerInvocationHandler(MBeanServerConnection connection, | ||
| 139 | ObjectName objectName, | ||
| 140 | boolean isMXBean) { | ||
| 141 | if (connection == null) { | ||
| 142 | throw new IllegalArgumentException("Null connection"); | ||
| 143 | } | ||
| 144 | if (objectName == null) { | ||
| 145 | throw new IllegalArgumentException("Null object name"); | ||
| 146 | } | ||
| 147 | this.connection = connection; | ||
| 148 | this.objectName = objectName; | ||
| 149 | this.isMXBean = isMXBean; | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * <p>The MBean server connection through which the methods of | ||
| 154 | * a proxy using this handler are forwarded.</p> | ||
| 155 | * | ||
| 156 | * @return the MBean server connection. | ||
| 157 | * | ||
| 158 | * @since 1.6 | ||
| 159 | */ | ||
| 160 | public MBeanServerConnection getMBeanServerConnection() { | ||
| 161 | return connection; | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 165 | * <p>The name of the MBean within the MBean server to which methods | ||
| 166 | * are forwarded. | ||
| 167 | * | ||
| 168 | * @return the object name. | ||
| 169 | * | ||
| 170 | * @since 1.6 | ||
| 171 | */ | ||
| 172 | public ObjectName getObjectName() { | ||
| 173 | return objectName; | ||
| 174 | } | ||
| 175 | |||
| 176 | /** | ||
| 177 | * <p>If true, the proxy is for an MXBean, and appropriate mappings | ||
| 178 | * are applied to method parameters and return values. | ||
| 179 | * | ||
| 180 | * @return whether the proxy is for an MXBean. | ||
| 181 | * | ||
| 182 | * @since 1.6 | ||
| 183 | */ | ||
| 184 | public boolean isMXBean() { | ||
| 185 | return isMXBean; | ||
| 186 | } | ||
| 187 | |||
| 188 | /** | ||
| 189 | * <p>Return a proxy that implements the given interface by | ||
| 190 | * forwarding its methods through the given MBean server to the | ||
| 191 | * named MBean. As of 1.6, the methods {@link | ||
| 192 | * JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class)} and | ||
| 193 | * {@link JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class, | ||
| 194 | * boolean)} are preferred to this method.</p> | ||
| 195 | * | ||
| 196 | * <p>This method is equivalent to {@link Proxy#newProxyInstance | ||
| 197 | * Proxy.newProxyInstance}<code>(interfaceClass.getClassLoader(), | ||
| 198 | * interfaces, handler)</code>. Here <code>handler</code> is the | ||
| 199 | * result of {@link #MBeanServerInvocationHandler new | ||
| 200 | * MBeanServerInvocationHandler(connection, objectName)}, and | ||
| 201 | * <code>interfaces</code> is an array that has one element if | ||
| 202 | * <code>notificationBroadcaster</code> is false and two if it is | ||
| 203 | * true. The first element of <code>interfaces</code> is | ||
| 204 | * <code>interfaceClass</code> and the second, if present, is | ||
| 205 | * <code>NotificationEmitter.class</code>. | ||
| 206 | * | ||
| 207 | * @param connection the MBean server to forward to. | ||
| 208 | * @param objectName the name of the MBean within | ||
| 209 | * <code>connection</code> to forward to. | ||
| 210 | * @param interfaceClass the management interface that the MBean | ||
| 211 | * exports, which will also be implemented by the returned proxy. | ||
| 212 | * @param notificationBroadcaster make the returned proxy | ||
| 213 | * implement {@link NotificationEmitter} by forwarding its methods | ||
| 214 | * via <code>connection</code>. A call to {@link | ||
| 215 | * NotificationBroadcaster#addNotificationListener} on the proxy will | ||
| 216 | * result in a call to {@link | ||
| 217 | * MBeanServerConnection#addNotificationListener(ObjectName, | ||
| 218 | * NotificationListener, NotificationFilter, Object)}, and likewise | ||
| 219 | * for the other methods of {@link NotificationBroadcaster} and {@link | ||
| 220 | * NotificationEmitter}. | ||
| 221 | * | ||
| 222 | * @param <T> allows the compiler to know that if the {@code | ||
| 223 | * interfaceClass} parameter is {@code MyMBean.class}, for example, | ||
| 224 | * then the return type is {@code MyMBean}. | ||
| 225 | * | ||
| 226 | * @return the new proxy instance. | ||
| 227 | * | ||
| 228 | * @see JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class) | ||
| 229 | */ | ||
| 230 | public static <T> T newProxyInstance(MBeanServerConnection connection, | ||
| 231 | ObjectName objectName, | ||
| 232 | Class<T> interfaceClass, | ||
| 233 | boolean notificationBroadcaster) { | ||
| 234 | final InvocationHandler handler = | ||
| 235 | new MBeanServerInvocationHandler(connection, objectName); | ||
| 236 | final Class<?>[] interfaces; | ||
| 237 | if (notificationBroadcaster) { | ||
| 238 | interfaces = | ||
| 239 | new Class<?>[] {interfaceClass, NotificationEmitter.class}; | ||
| 240 | } else | ||
| 241 | interfaces = new Class<?>[] {interfaceClass}; | ||
| 242 | |||
| 243 | Object proxy = | ||
| 244 | Proxy.newProxyInstance(interfaceClass.getClassLoader(), | ||
| 245 | interfaces, | ||
| 246 | handler); | ||
| 247 | return interfaceClass.cast(proxy); | ||
| 248 | } | ||
| 249 | |||
| 250 | public Object invoke(Object proxy, Method method, Object[] args) | ||
| 251 | throws Throwable { | ||
| 252 | final Class<?> methodClass = method.getDeclaringClass(); | ||
| 253 | |||
| 254 | if (methodClass.equals(NotificationBroadcaster.class) | ||
| 255 | || methodClass.equals(NotificationEmitter.class)) | ||
| 256 | return invokeBroadcasterMethod(proxy, method, args); | ||
| 257 | |||
| 258 | // local or not: equals, toString, hashCode | ||
| 259 | if (shouldDoLocally(proxy, method)) | ||
| 260 | return doLocally(proxy, method, args); | ||
| 261 | |||
| 262 | try { | ||
| 263 | if (isMXBean()) { | ||
| 264 | MXBeanProxy p = findMXBeanProxy(methodClass); | ||
| 265 | return p.invoke(connection, objectName, method, args); | ||
| 266 | } else { | ||
| 267 | final String methodName = method.getName(); | ||
| 268 | final Class<?>[] paramTypes = method.getParameterTypes(); | ||
| 269 | final Class<?> returnType = method.getReturnType(); | ||
| 270 | |||
| 271 | /* Inexplicably, InvocationHandler specifies that args is null | ||
| 272 | when the method takes no arguments rather than a | ||
| 273 | zero-length array. */ | ||
| 274 | final int nargs = (args == null) ? 0 : args.length; | ||
| 275 | |||
| 276 | if (methodName.startsWith("get") | ||
| 277 | && methodName.length() > 3 | ||
| 278 | && nargs == 0 | ||
| 279 | && !returnType.equals(Void.TYPE)) { | ||
| 280 | return connection.getAttribute(objectName, | ||
| 281 | methodName.substring(3)); | ||
| 282 | } | ||
| 283 | |||
| 284 | if (methodName.startsWith("is") | ||
| 285 | && methodName.length() > 2 | ||
| 286 | && nargs == 0 | ||
| 287 | && (returnType.equals(Boolean.TYPE) | ||
| 288 | || returnType.equals(Boolean.class))) { | ||
| 289 | return connection.getAttribute(objectName, | ||
| 290 | methodName.substring(2)); | ||
| 291 | } | ||
| 292 | |||
| 293 | if (methodName.startsWith("set") | ||
| 294 | && methodName.length() > 3 | ||
| 295 | && nargs == 1 | ||
| 296 | && returnType.equals(Void.TYPE)) { | ||
| 297 | Attribute attr = new Attribute(methodName.substring(3), args[0]); | ||
| 298 | connection.setAttribute(objectName, attr); | ||
| 299 | return null; | ||
| 300 | } | ||
| 301 | |||
| 302 | final String[] signature = new String[paramTypes.length]; | ||
| 303 | for (int i = 0; i < paramTypes.length; i++) | ||
| 304 | signature[i] = paramTypes[i].getName(); | ||
| 305 | return connection.invoke(objectName, methodName, | ||
| 306 | args, signature); | ||
| 307 | } | ||
| 308 | } catch (MBeanException e) { | ||
| 309 | throw e.getTargetException(); | ||
| 310 | } catch (RuntimeMBeanException re) { | ||
| 311 | throw re.getTargetException(); | ||
| 312 | } catch (RuntimeErrorException rre) { | ||
| 313 | throw rre.getTargetError(); | ||
| 314 | } | ||
| 315 | /* The invoke may fail because it can't get to the MBean, with | ||
| 316 | one of the these exceptions declared by | ||
| 317 | MBeanServerConnection.invoke: | ||
| 318 | - RemoteException: can't talk to MBeanServer; | ||
| 319 | - InstanceNotFoundException: objectName is not registered; | ||
| 320 | - ReflectionException: objectName is registered but does not | ||
| 321 | have the method being invoked. | ||
| 322 | In all of these cases, the exception will be wrapped by the | ||
| 323 | proxy mechanism in an UndeclaredThrowableException unless | ||
| 324 | it happens to be declared in the "throws" clause of the | ||
| 325 | method being invoked on the proxy. | ||
| 326 | */ | ||
| 327 | } | ||
| 328 | |||
| 329 | private static MXBeanProxy findMXBeanProxy(Class<?> mxbeanInterface) { | ||
| 330 | synchronized (mxbeanProxies) { | ||
| 331 | WeakReference<MXBeanProxy> proxyRef = | ||
| 332 | mxbeanProxies.get(mxbeanInterface); | ||
| 333 | MXBeanProxy p = (proxyRef == null) ? null : proxyRef.get(); | ||
| 334 | if (p == null) { | ||
| 335 | try { | ||
| 336 | p = new MXBeanProxy(mxbeanInterface); | ||
| 337 | } catch (IllegalArgumentException e) { | ||
| 338 | String msg = "Cannot make MXBean proxy for " + | ||
| 339 | mxbeanInterface.getName() + ": " + e.getMessage(); | ||
| 340 | IllegalArgumentException iae = | ||
| 341 | new IllegalArgumentException(msg, e.getCause()); | ||
| 342 | iae.setStackTrace(e.getStackTrace()); | ||
| 343 | throw iae; | ||
| 344 | } | ||
| 345 | mxbeanProxies.put(mxbeanInterface, | ||
| 346 | new WeakReference<MXBeanProxy>(p)); | ||
| 347 | } | ||
| 348 | return p; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | private static final WeakHashMap<Class<?>, WeakReference<MXBeanProxy>> | ||
| 352 | mxbeanProxies = new WeakHashMap<Class<?>, WeakReference<MXBeanProxy>>(); | ||
| 353 | |||
| 354 | private Object invokeBroadcasterMethod(Object proxy, Method method, | ||
| 355 | Object[] args) throws Exception { | ||
| 356 | final String methodName = method.getName(); | ||
| 357 | final int nargs = (args == null) ? 0 : args.length; | ||
| 358 | |||
| 359 | if (methodName.equals("addNotificationListener")) { | ||
| 360 | /* The various throws of IllegalArgumentException here | ||
| 361 | should not happen, since we know what the methods in | ||
| 362 | NotificationBroadcaster and NotificationEmitter | ||
| 363 | are. */ | ||
| 364 | if (nargs != 3) { | ||
| 365 | final String msg = | ||
| 366 | "Bad arg count to addNotificationListener: " + nargs; | ||
| 367 | throw new IllegalArgumentException(msg); | ||
| 368 | } | ||
| 369 | /* Other inconsistencies will produce ClassCastException | ||
| 370 | below. */ | ||
| 371 | |||
| 372 | NotificationListener listener = (NotificationListener) args[0]; | ||
| 373 | NotificationFilter filter = (NotificationFilter) args[1]; | ||
| 374 | Object handback = args[2]; | ||
| 375 | connection.addNotificationListener(objectName, | ||
| 376 | listener, | ||
| 377 | filter, | ||
| 378 | handback); | ||
| 379 | return null; | ||
| 380 | |||
| 381 | } else if (methodName.equals("removeNotificationListener")) { | ||
| 382 | |||
| 383 | /* NullPointerException if method with no args, but that | ||
| 384 | shouldn't happen because removeNL does have args. */ | ||
| 385 | NotificationListener listener = (NotificationListener) args[0]; | ||
| 386 | |||
| 387 | switch (nargs) { | ||
| 388 | case 1: | ||
| 389 | connection.removeNotificationListener(objectName, listener); | ||
| 390 | return null; | ||
| 391 | |||
| 392 | case 3: | ||
| 393 | NotificationFilter filter = (NotificationFilter) args[1]; | ||
| 394 | Object handback = args[2]; | ||
| 395 | connection.removeNotificationListener(objectName, | ||
| 396 | listener, | ||
| 397 | filter, | ||
| 398 | handback); | ||
| 399 | return null; | ||
| 400 | |||
| 401 | default: | ||
| 402 | final String msg = | ||
| 403 | "Bad arg count to removeNotificationListener: " + nargs; | ||
| 404 | throw new IllegalArgumentException(msg); | ||
| 405 | } | ||
| 406 | |||
| 407 | } else if (methodName.equals("getNotificationInfo")) { | ||
| 408 | |||
| 409 | if (args != null) { | ||
| 410 | throw new IllegalArgumentException("getNotificationInfo has " + | ||
| 411 | "args"); | ||
| 412 | } | ||
| 413 | |||
| 414 | MBeanInfo info = connection.getMBeanInfo(objectName); | ||
| 415 | return info.getNotifications(); | ||
| 416 | |||
| 417 | } else { | ||
| 418 | throw new IllegalArgumentException("Bad method name: " + | ||
| 419 | methodName); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | private boolean shouldDoLocally(Object proxy, Method method) { | ||
| 424 | final String methodName = method.getName(); | ||
| 425 | if ((methodName.equals("hashCode") || methodName.equals("toString")) | ||
| 426 | && method.getParameterTypes().length == 0 | ||
| 427 | && isLocal(proxy, method)) | ||
| 428 | return true; | ||
| 429 | if (methodName.equals("equals") | ||
| 430 | && Arrays.equals(method.getParameterTypes(), | ||
| 431 | new Class<?>[] {Object.class}) | ||
| 432 | && isLocal(proxy, method)) | ||
| 433 | return true; | ||
| 434 | return false; | ||
| 435 | } | ||
| 436 | |||
| 437 | private Object doLocally(Object proxy, Method method, Object[] args) { | ||
| 438 | final String methodName = method.getName(); | ||
| 439 | |||
| 440 | if (methodName.equals("equals")) { | ||
| 441 | |||
| 442 | if (this == args[0]) { | ||
| 443 | return true; | ||
| 444 | } | ||
| 445 | |||
| 446 | if (!(args[0] instanceof Proxy)) { | ||
| 447 | return false; | ||
| 448 | } | ||
| 449 | |||
| 450 | final InvocationHandler ihandler = | ||
| 451 | Proxy.getInvocationHandler(args[0]); | ||
| 452 | |||
| 453 | if (ihandler == null || | ||
| 454 | !(ihandler instanceof MBeanServerInvocationHandler)) { | ||
| 455 | return false; | ||
| 456 | } | ||
| 457 | |||
| 458 | final MBeanServerInvocationHandler handler = | ||
| 459 | (MBeanServerInvocationHandler)ihandler; | ||
| 460 | |||
| 461 | return connection.equals(handler.connection) && | ||
| 462 | objectName.equals(handler.objectName) && | ||
| 463 | proxy.getClass().equals(args[0].getClass()); | ||
| 464 | } else if (methodName.equals("toString")) { | ||
| 465 | return (isMXBean() ? "MX" : "M") + "BeanProxy(" + | ||
| 466 | connection + "[" + objectName + "])"; | ||
| 467 | } else if (methodName.equals("hashCode")) { | ||
| 468 | return objectName.hashCode()+connection.hashCode(); | ||
| 469 | } | ||
| 470 | |||
| 471 | throw new RuntimeException("Unexpected method name: " + methodName); | ||
| 472 | } | ||
| 473 | |||
| 474 | private static boolean isLocal(Object proxy, Method method) { | ||
| 475 | final Class<?>[] interfaces = proxy.getClass().getInterfaces(); | ||
| 476 | if(interfaces == null) { | ||
| 477 | return true; | ||
| 478 | } | ||
| 479 | |||
| 480 | final String methodName = method.getName(); | ||
| 481 | final Class<?>[] params = method.getParameterTypes(); | ||
| 482 | for (Class<?> intf : interfaces) { | ||
| 483 | try { | ||
| 484 | intf.getMethod(methodName, params); | ||
| 485 | return false; // found method in one of our interfaces | ||
| 486 | } catch (NoSuchMethodException nsme) { | ||
| 487 | // OK. | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | return true; // did not find in any interface | ||
| 492 | } | ||
| 493 | |||
| 494 | private final MBeanServerConnection connection; | ||
| 495 | private final ObjectName objectName; | ||
| 496 | private final boolean isMXBean; | ||
| 497 | } | ||