geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject cvs commit: incubator-geronimo/modules/kernel/src/java/org/apache/geronimo/kernel/service GeronimoMBeanEndpoint.java GeronimoMBeanEndpointConnection.java
Date Sun, 09 Nov 2003 20:01:12 GMT
dain        2003/11/09 12:01:12

  Modified:    modules/kernel/src/java/org/apache/geronimo/kernel/service
                        GeronimoMBeanEndpoint.java
                        GeronimoMBeanEndpointConnection.java
  Log:
  Added support for object based proxies instead of just interface base proxies.
  
  Revision  Changes    Path
  1.2       +4 -4      incubator-geronimo/modules/kernel/src/java/org/apache/geronimo/kernel/service/GeronimoMBeanEndpoint.java
  
  Index: GeronimoMBeanEndpoint.java
  ===================================================================
  RCS file: /home/cvs/incubator-geronimo/modules/kernel/src/java/org/apache/geronimo/kernel/service/GeronimoMBeanEndpoint.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- GeronimoMBeanEndpoint.java	6 Nov 2003 19:52:50 -0000	1.1
  +++ GeronimoMBeanEndpoint.java	9 Nov 2003 20:01:12 -0000	1.2
  @@ -245,9 +245,9 @@
           } catch (ClassNotFoundException e) {
               throw new IllegalArgumentException("Interface class could not be loaded: type="
+ type);
           }
  -        if (!iface.isInterface()) {
  -            throw new IllegalArgumentException("Interface class is not an interface: type="
+ type);
  -        }
  +//        if (!iface.isInterface()) {
  +//            throw new IllegalArgumentException("Interface class is not an interface:
type=" + type);
  +//        }
   
           // required
           required = source.required;
  
  
  
  1.2       +142 -90   incubator-geronimo/modules/kernel/src/java/org/apache/geronimo/kernel/service/GeronimoMBeanEndpointConnection.java
  
  Index: GeronimoMBeanEndpointConnection.java
  ===================================================================
  RCS file: /home/cvs/incubator-geronimo/modules/kernel/src/java/org/apache/geronimo/kernel/service/GeronimoMBeanEndpointConnection.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- GeronimoMBeanEndpointConnection.java	6 Nov 2003 19:52:50 -0000	1.1
  +++ GeronimoMBeanEndpointConnection.java	9 Nov 2003 20:01:12 -0000	1.2
  @@ -55,30 +55,29 @@
    */
   package org.apache.geronimo.kernel.service;
   
  -import java.lang.reflect.InvocationHandler;
   import java.lang.reflect.Method;
  -import java.lang.reflect.Proxy;
  -import java.util.Map;
  -import java.util.HashMap;
  -import javax.management.MBeanException;
  -import javax.management.ReflectionException;
  -import javax.management.RuntimeOperationsException;
  -import javax.management.RuntimeMBeanException;
  -import javax.management.RuntimeErrorException;
  +import java.lang.reflect.Modifier;
  +import java.util.Arrays;
   import javax.management.MBeanServer;
   import javax.management.ObjectName;
   
  +import org.apache.geronimo.kernel.jmx.InvokeMBean;
  +
  +import net.sf.cglib.proxy.Callbacks;
  +import net.sf.cglib.proxy.Enhancer;
  +import net.sf.cglib.proxy.Factory;
  +import net.sf.cglib.proxy.MethodInterceptor;
  +import net.sf.cglib.proxy.MethodProxy;
  +import net.sf.cglib.proxy.SimpleCallbacks;
  +import net.sf.cglib.proxy.SimpleFilter;
  +import net.sf.cglib.reflect.FastClass;
  +
   /**
    * This handles a connection to another mbean.
    *
    * @version $Revision$ $Date$
    */
  -class GeronimoMBeanEndpointConnection  {
  -    /**
  -     * Map from method proxies to mbeanInvoker.
  -     */
  -    private Map methodMap = new HashMap();
  -
  +class GeronimoMBeanEndpointConnection {
       /**
        * The MBean server to Invoke.
        */
  @@ -90,24 +89,29 @@
       private ObjectName objectName;
   
       /**
  -     * The interface for the proxy
  +     * A factory to create instances
        */
  -    private Class iface;
  +    private Factory factory;
   
       /**
  -     * Proxy to the to this connection.
  +     * Map from interface method ids to InvokeMBean objects.
        */
  -    private Object proxy;
  +    private InvokeMBean[] methodTable;
   
       /**
  -     * The invocation handler for the proxy
  +     * Is this connection open?
        */
  -    private ConnectionInvocationHandler invocationHandler;
  +    private boolean open = false;
   
       /**
  -     * Is this connection open?
  +     * Proxy to the to this connection.
        */
  -    private boolean open = false;
  +    private Object proxy;
  +
  +    /**
  +     * The invocation handler for the proxy
  +     */
  +    private ConnectionMethodInterceptor methodInterceptor;
   
       /**
        * Creates a new connection to the specified component using the specified interface.
  @@ -118,19 +122,51 @@
        */
       public GeronimoMBeanEndpointConnection(Class iface, MBeanServer server, ObjectName
objectName) {
           assert iface != null: "iface can not be null";
  -        assert iface.isInterface(): "iface must be an interface";
           assert server != null: "Server can not be null";
           assert objectName != null: "Object name can not be null";
  -        assert !objectName.isPattern(): "Object name can not be a pattern";
   
  -        this.iface = iface;
  +        if(Modifier.isFinal(iface.getModifiers())) {
  +            throw new IllegalArgumentException("Proxy interface cannot be a final class:
" + iface.getName());
  +        }
  +        if(objectName.isPattern()) {
  +            throw new IllegalArgumentException("Object name can not be a pattern");
  +        }
  +
           this.server = server;
           this.objectName = objectName;
   
  +        MethodInterceptor dummyInterceptor = new MethodInterceptor() {
  +            public Object intercept(Object obj, Method method, Object[] args, MethodProxy
proxy) throws Throwable {
  +                return null;
  +            }
  +        };
  +
  +        // get the factory
  +        Enhancer enhancer = new Enhancer();
  +        enhancer.setSuperclass(iface);
  +        enhancer.setCallbackFilter(new SimpleFilter(Callbacks.INTERCEPT));
  +        enhancer.setCallbacks(new SimpleCallbacks());
  +        factory = enhancer.create();
  +
  +        final Class javaClass = factory.newInstance(dummyInterceptor).getClass();
  +        FastClass fastClass = FastClass.create(javaClass);
  +        methodTable = new InvokeMBean[fastClass.getMaxIndex() + 1];
           Method[] methods = iface.getMethods();
           for (int i = 0; i < methods.length; i++) {
               Method method = methods[i];
  -            methodMap.put(method, new MBeanInvoker(method));
  +            if((method.getModifiers() & (Modifier.FINAL | Modifier.PUBLIC)) == Modifier.PUBLIC)
{
  +                int index = getSuperIndex(fastClass, method);
  +                methodTable[index] = new InvokeMBean(method, false, false);
  +            }
  +        }
  +
  +        try {
  +            methodTable[getSuperIndex(fastClass, javaClass.getMethod("equals", new Class[]{Object.class}))]
= new EqualsInvoke();
  +            methodTable[getSuperIndex(fastClass, javaClass.getMethod("hashCode", null))]
= new HashCodeInvoke();
  +            methodTable[getSuperIndex(fastClass, javaClass.getMethod("toString", null))]
= new ToStringInvoke(iface.getName());
  +        } catch (Exception e) {
  +            // this can not happen... all classes must implement equals, hashCode and toString
  +            throw new AssertionError(e);
           }
       }
   
  @@ -139,16 +175,15 @@
        */
       public synchronized void invalidate() {
           open = false;
  -        if(invocationHandler != null) {
  -            invocationHandler.invalidate();
  -            invocationHandler = null;
  +        if (methodInterceptor != null) {
  +            methodInterceptor.invalidate();
  +            methodInterceptor = null;
           }
           proxy = null;
   
           server = null;
           objectName = null;
  -        methodMap.clear();
  -        methodMap = null;
  +        methodTable = null;
           proxy = null;
       }
   
  @@ -173,11 +208,12 @@
        * Opens a connection to the component.  This cretes the proxy used to communicate
with the component
        */
       public synchronized void open() {
  -        if(open) {
  +        if (open) {
               throw new IllegalStateException("Connection is already open");
           }
  -        invocationHandler = new ConnectionInvocationHandler(new HashMap(methodMap), server,
objectName);
  -        proxy = Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, invocationHandler);
  +
  +        methodInterceptor = new ConnectionMethodInterceptor(methodTable, server, objectName);
  +        proxy = factory.newInstance(methodInterceptor);
           open = true;
       }
   
  @@ -185,41 +221,44 @@
        * Closes the connection to the component.
        */
       public synchronized void close() {
  -        if(!open) {
  +        if (!open) {
               throw new IllegalStateException("Connection is already closed");
           }
  -        invocationHandler.invalidate();
  -        invocationHandler = null;
  +        methodInterceptor.invalidate();
  +        methodInterceptor = null;
           proxy = null;
           open = false;
       }
   
  -    private static class ConnectionInvocationHandler implements InvocationHandler {
  +    private static class ConnectionMethodInterceptor implements MethodInterceptor {
           private boolean valid;
  -        private Map methodMap;
  +        private InvokeMBean[] methodTable;
           private MBeanServer server;
           private ObjectName objectName;
   
  -        public ConnectionInvocationHandler(Map methodMap, MBeanServer server, ObjectName
objectName) {
  +        public ConnectionMethodInterceptor(InvokeMBean[] methodTable, MBeanServer server,
ObjectName objectName) {
               valid = true;
  -            this.methodMap = methodMap;
  +            this.methodTable = methodTable;
               this.server = server;
               this.objectName = objectName;
           }
   
  -        public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable
{
  +        public Object intercept(Object obj, Method method, Object[] arguments, MethodProxy
proxy) throws Throwable {
               MBeanServer server;
               ObjectName objectName;
  -            MBeanInvoker mbeanInvoker;
  +            InvokeMBean mbeanInvoker;
   
               // grab references to the variables in a static block
               synchronized (this) {
                   if (!valid) {
  -                    throw new IllegalStateException("This proxy has been invalidated");
  +                    throw new IllegalStateException("The connection in this proxy has been
closed");
                   }
                   server = this.server;
                   objectName = this.objectName;
  -                mbeanInvoker = (MBeanInvoker) methodMap.get(method);
  +                mbeanInvoker = methodTable[proxy.getSuperIndex()];
  +            }
  +            if (mbeanInvoker == null) {
  +                throw new AssertionError("Unknown operation " + method);
               }
               return mbeanInvoker.invoke(server, objectName, arguments);
           }
  @@ -228,59 +267,72 @@
               valid = false;
               server = null;
               objectName = null;
  -            methodMap.clear();
  -            methodMap = null;
  +            methodTable = null;
           }
       }
   
  -    private static class MBeanInvoker {
  -        private final String methodName;
  -        private final String[] argumentTypes;
  -        private final Class[] declaredExceptions;
  +    private static final class HashCodeInvoke extends InvokeMBean {
  +        public HashCodeInvoke() {
  +            super("hashCode", new String[0], new Class[0], false, false, 0);
  +        }
  +
  +        public Object invoke(MBeanServer server, ObjectName objectName, Object[] arguments)
throws Throwable {
  +            return new Integer(objectName.hashCode());
  +        }
  +    }
   
  -        public MBeanInvoker(Method method) {
  -            methodName = method.getName();
  +    private static final class EqualsInvoke extends InvokeMBean {
  +        public EqualsInvoke() {
  +            super("hashCode", new String[]{"java.lang.Object"}, new Class[]{Object.class},
false, false, 1);
  +        }
   
  -            // conver the parameters to a MBeanServer friendly string array
  -            Class[] parameters = method.getParameterTypes();
  -            argumentTypes = new String[parameters.length];
  -            for (int i = 0; i < parameters.length; i++) {
  -                argumentTypes[i] = parameters[i].getName();
  -            }
  +        public Object invoke(MBeanServer server, ObjectName objectName, Object[] arguments)
throws Throwable {
  +            return new Boolean(objectName.equals(arguments[0]));
  +        }
  +    }
  +
  +
  +    private static final class ToStringInvoke extends InvokeMBean {
  +        private final String interfaceName;
   
  -            declaredExceptions = method.getExceptionTypes();
  +        public ToStringInvoke(String interfaceName) {
  +            super("toString", new String[0], new Class[0], false, false, 0);
  +            this.interfaceName = "[" + interfaceName + ": ";
           }
   
           public Object invoke(MBeanServer server, ObjectName objectName, Object[] arguments)
throws Throwable {
  -            try {
  -                return server.invoke(objectName, methodName, arguments, argumentTypes);
  -            } catch (Throwable t) {
  -                Throwable throwable = t;
  -                while (true) {
  -                    for (int i = 0; i < declaredExceptions.length; i++) {
  -                        Class declaredException = declaredExceptions[i];
  -                        if (declaredException.isInstance(throwable)) {
  -                            throw throwable;
  -                        }
  -                    }
  -
  -                    // Unwrap the exceptions we understand
  -                    if (throwable instanceof MBeanException) {
  -                        throwable = (((MBeanException) throwable).getTargetException());
  -                    } else if (throwable instanceof ReflectionException) {
  -                        throwable = (((ReflectionException) throwable).getTargetException());
  -                    } else if (throwable instanceof RuntimeOperationsException) {
  -                        throwable = (((RuntimeOperationsException) throwable).getTargetException());
  -                    } else if (throwable instanceof RuntimeMBeanException) {
  -                        throwable = (((RuntimeMBeanException) throwable).getTargetException());
  -                    } else if (throwable instanceof RuntimeErrorException) {
  -                        throwable = (((RuntimeErrorException) throwable).getTargetError());
  -                    } else {
  -                        // don't know how to unwrap this, just throw it
  -                        throw throwable;
  -                    }
  -                }
  +            return interfaceName + objectName + "]";
  +        }
  +    }
  +
  +
  +    private static String ACCESS_PREFIX = "CGLIB$$ACCESS_";
  +
  +    /**
  +     * Returns the name of the synthetic method created by CGLIB which is
  +     * used by invokesuper to invoke the superclass
  +     * (non-intercepted) method implementation. The parameter types are
  +     * guaranteed to be the same.
  +     * @param enhancedClass the class generated by Enhancer
  +     * @param method the original method; only the name and parameter types are used.
  +     * @return the name of the synthetic proxy method, or null if no matching method can
be found
  +     */
  +    public static int getSuperIndex(FastClass enhancedClass, Method method) {
  +        String prefix = ACCESS_PREFIX + method.getName() + "_";
  +        int lastUnderscore = prefix.length() - 1;
  +        Class[] params = method.getParameterTypes();
  +
  +        Method[] methods = enhancedClass.getJavaClass().getDeclaredMethods();
  +        for (int i = 0; i < methods.length; i++) {
  +            String name = methods[i].getName();
  +            Class[] parameterTypes = methods[i].getParameterTypes();
  +            if (name.startsWith(prefix) &&
  +                    name.lastIndexOf('_') == lastUnderscore &&
  +                    Arrays.equals(parameterTypes, params)) {
  +                return enhancedClass.getIndex(name, parameterTypes);
               }
           }
  +        throw new IllegalArgumentException("Method not found on enhancedClass:" +
  +                " enhancedClass=" + enhancedClass.getJavaClass() + " method=" + method);
       }
   }
  
  
  

Mime
View raw message