Save This Page
Home » jboss-5.0.0.CR1-src » org.jboss.mx » util » [javadoc | source]
    1   /*
    2   * JBoss, Home of Professional Open Source
    3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4   * by the @authors tag. See the copyright.txt in the distribution for a
    5   * full listing of individual contributors.
    6   *
    7   * This is free software; you can redistribute it and/or modify it
    8   * under the terms of the GNU Lesser General Public License as
    9   * published by the Free Software Foundation; either version 2.1 of
   10   * the License, or (at your option) any later version.
   11   *
   12   * This software is distributed in the hope that it will be useful,
   13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15   * Lesser General Public License for more details.
   16   *
   17   * You should have received a copy of the GNU Lesser General Public
   18   * License along with this software; if not, write to the Free
   19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21   */
   22   package org.jboss.mx.util;
   23   
   24   import java.io.Externalizable;
   25   import java.io.IOException;
   26   import java.io.ObjectInput;
   27   import java.io.ObjectOutput;
   28   import java.lang.reflect.InvocationHandler;
   29   import java.lang.reflect.Method;
   30   import java.lang.reflect.Proxy;
   31   import java.security.AccessController;
   32   import java.security.PrivilegedAction;
   33   import java.util.HashMap;
   34   
   35   import javax.management.Attribute;
   36   import javax.management.MBeanAttributeInfo;
   37   import javax.management.MBeanInfo;
   38   import javax.management.MBeanServer;
   39   import javax.management.MBeanServerConnection;
   40   import javax.management.MalformedObjectNameException;
   41   import javax.management.ObjectName;
   42   
   43   /**
   44    * A factory for producing MBean proxies.
   45    *
   46    * <p>Created proxies will also implement {@link org.jboss.mx.util.MBeanProxyInstance}
   47    * allowing access to the proxies configuration.
   48    * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>.
   49    * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>.
   50    * @author <a href="mailto:adrian.brock@happeningtimes.com">Adrian Brock</a>.
   51    * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
   52    * @version <tt>$Revision: 42126 $</tt>
   53    */
   54   public class MBeanProxyExt
   55      implements InvocationHandler, MBeanProxyInstance, Externalizable
   56   {
   57      /** The serialVersionUID */
   58      private static final long serialVersionUID = -2942844863242742655L;
   59   
   60      /**
   61       * The remote MBeanServerConnection
   62       */
   63      public static MBeanServerConnection remote;
   64      
   65      /**
   66       * The server to proxy invoke calls to.
   67       */
   68      private MBeanServerConnection server;
   69   
   70      /**
   71       * The name of the object to invoke.
   72       */
   73      private ObjectName name;
   74   
   75      /**
   76       * The MBean's attributes
   77       */
   78      private transient final HashMap attributeMap = new HashMap();
   79      /**
   80       * Have the attributes been retrieved
   81       */
   82      private transient boolean inited = false;
   83   
   84      /**
   85       * For externalizable
   86       */
   87      public MBeanProxyExt()
   88      {
   89      }
   90      
   91      /**
   92       * Construct an MBeanProxy.
   93       */
   94      MBeanProxyExt(final ObjectName name, final MBeanServer server, boolean lazyInit)
   95      {
   96         this.name = name;
   97         this.server = server;
   98         if (lazyInit == false)
   99            init();
  100      }
  101   
  102      /**
  103       * Used when args is null.
  104       */
  105      private static final Object EMPTY_ARGS[] = {};
  106   
  107      /**
  108       * Invoke the configured MBean via the target MBeanServer and decode any
  109       * resulting JMX exceptions that are thrown.
  110       */
  111      public Object invoke(final Object proxy,
  112         final Method method,
  113         final Object[] args)
  114         throws Throwable
  115      {
  116         // if the method belongs to ProxyInstance, then invoke locally
  117         Class type = method.getDeclaringClass();
  118         if (type == MBeanProxyInstance.class || type == Object.class)
  119         {
  120            return method.invoke(this, args);
  121         }
  122   
  123         String methodName = method.getName();
  124   
  125         // Get attribute
  126         if (methodName.startsWith("get") && args == null)
  127         {
  128            if (inited == false)
  129               init();
  130   
  131            String attrName = methodName.substring(3);
  132            MBeanAttributeInfo info = (MBeanAttributeInfo) attributeMap.get(attrName);
  133            if (info != null)
  134            {
  135               String retType = method.getReturnType().getName();
  136               if (retType.equals(info.getType()))
  137               {
  138                  try
  139                  {
  140                     return server.getAttribute(name, attrName);
  141                  }
  142                  catch (Exception e)
  143                  {
  144                     throw JMXExceptionDecoder.decode(e);
  145                  }
  146               }
  147            }
  148         }
  149   
  150         // Is attribute
  151         else if (methodName.startsWith("is") && args == null)
  152         {
  153            if (inited == false)
  154               init();
  155   
  156            String attrName = methodName.substring(2);
  157            MBeanAttributeInfo info = (MBeanAttributeInfo) attributeMap.get(attrName);
  158            if (info != null && info.isIs())
  159            {
  160               Class retType = method.getReturnType();
  161               if (retType.equals(Boolean.class) || retType.equals(Boolean.TYPE))
  162               {
  163                  try
  164                  {
  165                     return server.getAttribute(name, attrName);
  166                  }
  167                  catch (Exception e)
  168                  {
  169                     throw JMXExceptionDecoder.decode(e);
  170                  }
  171               }
  172            }
  173         }
  174   
  175         // Set attribute
  176         else if (methodName.startsWith("set") && args != null && args.length == 1)
  177         {
  178            if (inited == false)
  179               init();
  180   
  181            String attrName = methodName.substring(3);
  182            MBeanAttributeInfo info = (MBeanAttributeInfo) attributeMap.get(attrName);
  183            if (info != null && method.getReturnType() == Void.TYPE)
  184            {
  185               try
  186               {
  187                  server.setAttribute(name, new Attribute(attrName, args[0]));
  188                  return null;
  189               }
  190               catch (Exception e)
  191               {
  192                  throw JMXExceptionDecoder.decode(e);
  193               }
  194            }
  195         }
  196   
  197         // Operation
  198   
  199         // convert the parameter types to strings for JMX
  200         Class[] types = method.getParameterTypes();
  201         String[] sig = new String[types.length];
  202         for (int i = 0; i < types.length; i++)
  203         {
  204            sig[i] = types[i].getName();
  205         }
  206   
  207         // invoke the server and decode JMX exceptions
  208         try
  209         {
  210            return server.invoke(name, methodName, args == null ? EMPTY_ARGS : args, sig);
  211         }
  212         catch (Exception e)
  213         {
  214            throw JMXExceptionDecoder.decode(e);
  215         }
  216      }
  217   
  218   
  219      ///////////////////////////////////////////////////////////////////////////
  220      //                          MBeanProxyInstance                           //
  221      ///////////////////////////////////////////////////////////////////////////
  222   
  223      public final ObjectName getMBeanProxyObjectName()
  224      {
  225         return name;
  226      }
  227   
  228      public final MBeanServer getMBeanProxyMBeanServer()
  229      {
  230         if (server instanceof MBeanServer == false)
  231            throw new IllegalStateException("This operation is not available for an MBeanServerConnection");
  232         return (MBeanServer) server;
  233      }
  234   
  235      public final MBeanServerConnection getMBeanProxyMBeanServerConnection()
  236      {
  237         return server;
  238      }
  239   
  240      ///////////////////////////////////////////////////////////////////////////
  241      //                          Object Overrides                             //
  242      ///////////////////////////////////////////////////////////////////////////
  243      
  244      /**
  245       * We need to override this because by default equals returns false when
  246       * called on the proxy object and then relayed here.
  247       */
  248      public boolean equals(Object that)
  249      {
  250         if (that == null) return false;
  251         if (that == this) return true;
  252         
  253         // check if 'that' is an MBeanProxyExt or a Proxy instance
  254         // that implements the MBeanProxyInstance interface
  255         if (that instanceof MBeanProxyInstance)
  256         {
  257            MBeanProxyInstance proxy = (MBeanProxyInstance) that;
  258            
  259            // assume equality if both the MBeanServer and ObjectName match
  260            if (name.equals(proxy.getMBeanProxyObjectName()) &&
  261               server.equals(proxy.getMBeanProxyMBeanServer()))
  262            {
  263               return true;
  264            }
  265         }
  266         return false;
  267      }
  268   
  269      /**
  270       * As with equals, use the MBeanServer + ObjectName to calculate the
  271       * hashCode
  272       */
  273      public int hashCode()
  274      {
  275         return name.hashCode() * 31 + server.hashCode();
  276      }
  277   
  278      /**
  279       * avoid the default printout, e.g. org.jboss.mx.util.MBeanProxyExt@120540c
  280       */
  281      public String toString()
  282      {
  283         StringBuffer sbuf = new StringBuffer(128);
  284   
  285         sbuf.append("MBeanProxyExt[").append(name.toString()).append(']');
  286   
  287         return sbuf.toString();
  288      }
  289   
  290      ///////////////////////////////////////////////////////////////////////////
  291      //                            Factory Methods                            //
  292      ///////////////////////////////////////////////////////////////////////////
  293   
  294      /**
  295       * Create an MBean proxy.
  296       * @param intf The interface which the proxy will implement.
  297       * @param name A string used to construct the ObjectName of the MBean to
  298       * proxy to.
  299       * @return A MBean proxy.
  300       * @throws javax.management.MalformedObjectNameException Invalid object
  301       * name.
  302       */
  303      public static Object create(final Class intf, final String name)
  304         throws MalformedObjectNameException
  305      {
  306         return create(intf, new ObjectName(name));
  307      }
  308   
  309      /**
  310       * Create an MBean proxy.
  311       * @param intf The interface which the proxy will implement.
  312       * @param name A string used to construct the ObjectName of the MBean to
  313       * proxy to.
  314       * @param server The MBeanServer that contains the MBean to proxy to.
  315       * @return A MBean proxy.
  316       * @throws javax.management.MalformedObjectNameException Invalid object
  317       * name.
  318       */
  319      public static Object create(final Class intf,
  320         final String name,
  321         final MBeanServer server)
  322         throws MalformedObjectNameException
  323      {
  324         return create(intf, new ObjectName(name), server);
  325      }
  326   
  327      /**
  328       * Create an MBean proxy.
  329       * @param intf The interface which the proxy will implement.
  330       * @param name The name of the MBean to proxy invocations to.
  331       * @return A MBean proxy.
  332       */
  333      public static Object create(final Class intf, final ObjectName name)
  334      {
  335         return create(intf, name, MBeanServerLocator.locateJBoss());
  336      }
  337   
  338      /**
  339       * Create an MBean proxy.
  340       * @param intf The interface which the proxy will implement.
  341       * @param name The name of the MBean to proxy invocations to.
  342       * @param server The MBeanServer that contains the MBean to proxy to.
  343       * @return A MBean proxy.
  344       */
  345      public static Object create(final Class intf,
  346         final ObjectName name,
  347         final MBeanServer server)
  348      {
  349         return create(intf, name, server, false);
  350      }
  351   
  352      /**
  353       * Create an MBean proxy.
  354       * @param intf The interface which the proxy will implement.
  355       * @param name The name of the MBean to proxy invocations to.
  356       * @param server The MBeanServer that contains the MBean to proxy to.
  357       * @param lazyInit - a flag indicating if the mbean attribute info should
  358       *    be retrieved when the proxy is created.
  359       * @return A MBean proxy.
  360       */
  361      public static Object create(final Class intf, final ObjectName name,
  362         final MBeanServer server, boolean lazyInit)
  363      {
  364         // CL which delegates to MBeanProxyInstance's cl for it's class resolution
  365         PrivilegedAction action = new PrivilegedAction()
  366         {
  367            public Object run()
  368            {
  369               ClassLoader cl = new ClassLoader(intf.getClassLoader())
  370               {
  371                  public Class loadClass(final String className) throws ClassNotFoundException
  372                  {
  373                     try
  374                     {
  375                        return super.loadClass(className);
  376                     }
  377                     catch (ClassNotFoundException e)
  378                     {
  379                        // only allow loading of MBeanProxyInstance from this loader
  380                        if (className.equals(MBeanProxyInstance.class.getName()))
  381                        {
  382                           return MBeanProxyInstance.class.getClassLoader().loadClass(className);
  383                        }
  384                        // was some other classname, throw the CNFE
  385                        throw e;
  386                     }
  387                  }
  388               };
  389               return cl;
  390            }
  391         };
  392         ClassLoader cl = (ClassLoader) AccessController.doPrivileged(action);
  393         Class[] ifaces = {MBeanProxyInstance.class, intf};
  394         InvocationHandler handler = new MBeanProxyExt(name, server, lazyInit);
  395         return Proxy.newProxyInstance(cl, ifaces, handler);
  396      }
  397   
  398      /**
  399       * Retrieve the mbean MBeanAttributeInfo
  400       */
  401      private synchronized void init()
  402      {
  403         // The MBean's attributes
  404         inited = true;
  405         try
  406         {
  407            MBeanInfo info = server.getMBeanInfo(name);
  408            MBeanAttributeInfo[] attributes = info.getAttributes();
  409   
  410            for (int i = 0; i < attributes.length; ++i)
  411               attributeMap.put(attributes[i].getName(), attributes[i]);
  412         }
  413         catch (Exception e)
  414         {
  415            throw new RuntimeException("Error creating MBeanProxy: " + name, e);
  416         }
  417      }
  418   
  419      public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
  420      {
  421         name = (ObjectName) in.readObject();
  422         server = (MBeanServerConnection) in.readObject();
  423      }
  424   
  425   
  426      public void writeExternal(ObjectOutput out) throws IOException
  427      {
  428         out.writeObject(name);
  429         if (remote != null)
  430            out.writeObject(remote);
  431         else
  432            out.writeObject(server); // This will fail for a normal MBeanServer
  433      }
  434   }

Save This Page
Home » jboss-5.0.0.CR1-src » org.jboss.mx » util » [javadoc | source]