You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jd...@apache.org on 2003/08/30 22:12:23 UTC

cvs commit: incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/jmx MBeanProxyHandler.java MBeanProxyFactory.java ObjectNameFactory.java

jdillon     2003/08/30 13:12:23

  Modified:    modules/common/src/java/org/apache/geronimo/common/jmx
                        MBeanProxyFactory.java ObjectNameFactory.java
  Added:       modules/common/src/java/org/apache/geronimo/common/jmx
                        MBeanProxyHandler.java
  Log:
   o Replaced MPF impl with a version that checks more details before
     determining what to do
   o What to be done is encapsulated into a Task, which can be cached
     for future use
   * Tests need to be expanded
  
  Revision  Changes    Path
  1.3       +43 -36    incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/jmx/MBeanProxyFactory.java
  
  Index: MBeanProxyFactory.java
  ===================================================================
  RCS file: /home/cvs/incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/jmx/MBeanProxyFactory.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- MBeanProxyFactory.java	30 Aug 2003 17:49:17 -0000	1.2
  +++ MBeanProxyFactory.java	30 Aug 2003 20:12:23 -0000	1.3
  @@ -61,47 +61,73 @@
   import javax.management.MBeanServer;
   import javax.management.ObjectName;
   
  +import org.apache.geronimo.common.NullArgumentException;
  +
   /**
    * Creates a dynamic proxy to an MBean by ObjectName.
    *
    * The interface type and object existance is not enforced during construction.
    * Instead, if a method is invoked on the proxy and there is no object registered
    * with the assigned name, an InvocationTargetException is thrown, which contains
  - * an InstanceNotFoundException.  If an interface method that is not implemented by
  + * an InstanceNotFoundException.
  + *
  + * If an interface method that is not implemented by
    * the MBean is invoked, an InvocationTargetException is thrown, which contains an
    * NoSuchMethodException.
    *
    * @version $Revision$ $Date$
    */
  -public final class MBeanProxyFactory
  +public class MBeanProxyFactory
   {
  -    /** Disallow instantation. */
  -    private MBeanProxyFactory() {}
  -
       /**
        * Creates an MBean proxy using the specified interface to the objectName.
        *
  -     * @param iface         The interface to implement for this proxy
  +     * @param type          The interface to implement for this proxy
        * @param server        The MBeanServer in which the object is registered
        * @param objectName    The objectName of the MBean to proxy
        * @return              The new MBean proxy, which implemnts the specified interface.
        */
  -    public static Object getProxy(final Class iface,
  -                                  final MBeanServer server,
  -                                  final ObjectName objectName)
  +    public static Object create(final Class type,
  +                                final MBeanServer server,
  +                                final ObjectName objectName)
       {
  -        assert iface != null;
  -        assert iface.isInterface();
  -        assert server != null;
  +        if (type == null) {
  +            throw new NullArgumentException("type");
  +        }
  +        if (!type.isInterface()) {
  +            throw new IllegalArgumentException("Type is not an interface: " + type);
  +        }
  +        if (server == null) {
  +            throw new NullArgumentException("server");
  +        }
           
  -        ClassLoader cl = iface.getClassLoader();
  -        LocalHandler handler =  new LocalHandler(iface, server, objectName);
  +        ClassLoader cl = type.getClassLoader();
  +        Class[] types = { type, MBeanProxy.class };
  +        
  +        MBeanProxyHandler handler =  new MBeanProxyHandler(server, objectName);
  +        
  +        return Proxy.newProxyInstance(cl, types, handler);
  +    }
  +    
  +    /**
  +     * Creates an MBean proxy using the specified interface to the objectName.
  +     *
  +     * @param tyep          The interface to implement for this proxy
  +     * @param objectName    The objectName of the MBean to proxy
  +     * @return              The new MBean proxy, which implemnts the specified interface.
  +     */
  +    public static Object create(final Class type, final ObjectName objectName)
  +    {
  +        MBeanServer server = MBeanServerLocator.locate();
  +        assert server != null;
           
  -        return Proxy.newProxyInstance(
  -            cl, new Class[] { iface, MBeanProxy.class }, handler
  -        );
  +        return create(type, server, objectName);
       }
       
  +    /**
  +     * An interface which all proxies created by {@link MBeanProxyFactory}
  +     * will implement in addition to the requested interface.
  +     */
       public static interface MBeanProxy
       {
           /**
  @@ -117,24 +143,5 @@
            * @return   The ObjectName for this proxy.
            */
           MBeanServer getMBeanProxyMBeanServer();
  -    }
  -    
  -    private static class LocalHandler 
  -        extends AbstractMBeanProxyHandler
  -    {
  -        private ObjectName objectName;
  -        
  -        public LocalHandler(final Class iface,
  -                            final MBeanServer server,
  -                            final ObjectName objectName)
  -        {
  -            super(iface, server);
  -            
  -            this.objectName = objectName;
  -        }
  -        
  -        public ObjectName getObjectName() {
  -            return objectName;
  -        }
       }
   }
  
  
  
  1.2       +4 -0      incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/jmx/ObjectNameFactory.java
  
  Index: ObjectNameFactory.java
  ===================================================================
  RCS file: /home/cvs/incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/jmx/ObjectNameFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ObjectNameFactory.java	30 Aug 2003 16:32:38 -0000	1.1
  +++ ObjectNameFactory.java	30 Aug 2003 20:12:23 -0000	1.2
  @@ -75,6 +75,10 @@
    */
   public class ObjectNameFactory
   {
  +    //
  +    // TODO: Replace Error with InvalidArgumentException
  +    //
  +    
       public static ObjectName create(String name) {
           try {
               return new ObjectName(name);
  
  
  
  1.1                  incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/jmx/MBeanProxyHandler.java
  
  Index: MBeanProxyHandler.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Geronimo" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Geronimo", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * ====================================================================
   */
  
  package org.apache.geronimo.common.jmx;
  
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  
  import java.util.Map;
  import java.util.HashMap;
  
  import javax.management.MBeanServer;
  import javax.management.ObjectName;
  import javax.management.Attribute;
  import javax.management.MBeanInfo;
  import javax.management.MBeanAttributeInfo;
  import javax.management.MBeanOperationInfo;
  import javax.management.MBeanException;
  import javax.management.ReflectionException;
  import javax.management.RuntimeOperationsException;
  import javax.management.RuntimeMBeanException;
  import javax.management.RuntimeErrorException;
  
  import org.apache.geronimo.common.NullArgumentException;
  
  /**
   * This class handles invocations for MBean proxies.
   *
   * @version $Revision: 1.1 $ $Date: 2003/08/30 20:12:23 $
   */
  public class MBeanProxyHandler
      implements InvocationHandler, MBeanProxyFactory.MBeanProxy
  {
      protected final MBeanServer server;
      protected ObjectName target;
      protected Map attributeMap;
      protected Map taskCache;
      
      public MBeanProxyHandler(final MBeanServer server,
                               final ObjectName target)
      {
          if (server == null) {
              throw new NullArgumentException("server");
          }
          // target can be null
          
          this.server = server;
          this.target = target;
      }
      
      public Object invoke(final Object proxy, final Method method, final Object[] args)
          throws Throwable
      {
          assert proxy != null;
          assert method != null;
          
          Class declaringClass = method.getDeclaringClass();
          
          // if the method belongs to MBeanProxy, then invoke locally
          if (declaringClass == MBeanProxyFactory.MBeanProxy.class) {
              return method.invoke(this, args);
          }
          
          //
          // TODO: Handle DynamicMBean.class
          //
          
          try {
              return getTask(method, args).execute(proxy, method, args);
          }
          catch (Throwable t) {
              Throwable decoded = JMXExceptionDecoder.decode(t);
              
              // If it is a RuntimeException or Error just toss is
              if (decoded instanceof RuntimeException) {
                  throw (RuntimeException)decoded;
              }
              if (decoded instanceof Error) {
                  throw (Error)decoded;
              }
              
              // Attempt to throw a declared exception
              Class[] declared = method.getExceptionTypes();
              for (int i=0; i < declared.length; i++) {
                  Class type = declared[i];
                  if (type.isInstance(decoded)) {
                      throw decoded;
                  }
              }
              
              // Else we don't have much choice, so just toss the original
              throw t;
          }
      }
      
      /////////////////////////////////////////////////////////////////////////
      //                                Tasks                                //
      /////////////////////////////////////////////////////////////////////////
      
      protected interface Task
      {
          Object execute(Object proxy, Method method, Object[] args) throws Throwable;
      }
      
      protected class GetAttributeTask
          implements Task
      {
          private MBeanAttributeInfo info;
          
          public GetAttributeTask(MBeanAttributeInfo info)
          {
              this.info = info;
          }
          
          public Object execute(final Object proxy, final Method method, final Object[] args)
              throws Throwable
          {
              return server.getAttribute(
                  getMBeanProxyObjectName(), 
                  info.getName()
              );
          }
      }
      
      protected class SetAttributeTask
          implements Task
      {
          private MBeanAttributeInfo info;
          
          public SetAttributeTask(MBeanAttributeInfo info)
          {
              this.info = info;
          }
          
          public Object execute(final Object proxy, final Method method, final Object[] args)
              throws Throwable
          {
              server.setAttribute(
                  getMBeanProxyObjectName(),
                  new Attribute(info.getName(), args[0])
              );
              
              return null;
          }
      }
  
      protected class InvokeOperationTask
          implements Task
      {
          public Object execute(final Object proxy, final Method method, final Object[] args)
              throws Throwable
          {
              String[] signature = null;
              
              if (args != null) {
                  signature = new String[args.length];
                  Class[] types = method.getParameterTypes();
                  
                  for (int i=0; i<types.length; i++) {
                      signature[i] = types[i].getName();
                  }
              }
              
              return server.invoke(
                  getMBeanProxyObjectName(),
                  method.getName(),
                  args,
                  signature
              );
          }
      }
      
      protected Task createTask(final Method method, final Object[] args)
          throws Exception
      {
          assert method != null;
          
          if (taskCache == null) {
              // Allow sub-class overrides
              ObjectName objectName = getMBeanProxyObjectName();
              
              // Get information about the target
              MBeanInfo info = server.getMBeanInfo(objectName);
              
              // Initialize the task cache
              taskCache = new HashMap();
              
              // Load up the attribute mapping
              attributeMap = new HashMap();
              MBeanAttributeInfo[] attributes = info.getAttributes();
              for (int i=0; i<attributes.length; i++) {
                  attributeMap.put(attributes[i].getName(), attributes[i]);
              }
          }
          
          String methodName = method.getName();
          
          // Check for getters
          if (args == null) {
              if (methodName.startsWith("get")) {
                  String attrName = methodName.substring(3, methodName.length());
                  MBeanAttributeInfo info = (MBeanAttributeInfo)attributeMap.get(attrName);
                  if (info != null) {
                      //
                      // TODO: Check that return value is what is expected
                      //
                      return new GetAttributeTask(info);
                  }
              }
              else if (methodName.startsWith("is")) {
                  String attrName = methodName.substring(2, methodName.length());
                  MBeanAttributeInfo info = (MBeanAttributeInfo)attributeMap.get(attrName);
                  if (info != null && info.isIs()) {
                      // is getters must return booleans
                      Class rtype = method.getReturnType();
                      if (rtype == Boolean.class || rtype == boolean.class) {
                          return new GetAttributeTask(info);
                      }
                  }
              }
          }
          
          // Check for setters
          else if (args.length == 1 && methodName.startsWith("set")) {
              String attrName = methodName.substring(3, methodName.length());
              MBeanAttributeInfo info = (MBeanAttributeInfo)attributeMap.get(attrName);
              if (info != null) {
                  // setters must return void
                  Class rtype = method.getReturnType();
                  if (rtype == void.class) {
                      return new SetAttributeTask(info);
                  }
              }
          }
          
          // Else it will pass through as an attempted operation
          return new InvokeOperationTask();
      }
      
      protected Task getTask(final Method method, final Object[] args)
          throws Exception
      {
          // Key off of method name & arg count
          Object key = method.getName() + (args == null ? 0 : args.length);
          
          // Check if there is a cached task
          Task task = null;
          if (taskCache != null) {
              task = (Task)taskCache.get(key);
          }
          
          // If not create one and cache it
          if (task == null) {
              task = createTask(method, args);
              taskCache.put(key, task);
          }
          
          return task;
      }
      
      
      /////////////////////////////////////////////////////////////////////////
      //                              MBeanProxy                             //
      /////////////////////////////////////////////////////////////////////////
      
      //
      // TODO: Replace with a MBeanProxyContext interface
      //
      
      public ObjectName getMBeanProxyObjectName()
      {
          return target;
      }
      
      public MBeanServer getMBeanProxyMBeanServer()
      {
          return server;
      }
  }