Save This Page
Home » jboss-5.0.0.CR1-src » org.jboss.mx » server » [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.server;
   23   
   24   import java.lang.reflect.Method;
   25   import java.lang.reflect.Modifier;
   26   import java.util.ArrayList;
   27   import java.util.HashMap;
   28   import java.util.Iterator;
   29   import java.util.List;
   30   import java.util.Map;
   31   
   32   import javax.management.Attribute;
   33   import javax.management.AttributeList;
   34   import javax.management.AttributeNotFoundException;
   35   import javax.management.Descriptor;
   36   import javax.management.InvalidAttributeValueException;
   37   import javax.management.JMRuntimeException;
   38   import javax.management.ListenerNotFoundException;
   39   import javax.management.MBeanAttributeInfo;
   40   import javax.management.MBeanException;
   41   import javax.management.MBeanInfo;
   42   import javax.management.MBeanNotificationInfo;
   43   import javax.management.MBeanOperationInfo;
   44   import javax.management.MBeanParameterInfo;
   45   import javax.management.MBeanRegistration;
   46   import javax.management.MBeanServer;
   47   import javax.management.NotificationBroadcaster;
   48   import javax.management.NotificationEmitter;
   49   import javax.management.NotificationFilter;
   50   import javax.management.NotificationListener;
   51   import javax.management.ObjectName;
   52   import javax.management.ReflectionException;
   53   import javax.management.RuntimeErrorException;
   54   import javax.management.RuntimeMBeanException;
   55   import javax.management.RuntimeOperationsException;
   56   import javax.management.modelmbean.ModelMBeanInfo;
   57   import javax.management.modelmbean.ModelMBeanInfoSupport;
   58   
   59   import org.jboss.logging.Logger;
   60   import org.jboss.mx.interceptor.AttributeDispatcher;
   61   import org.jboss.mx.interceptor.Interceptor;
   62   import org.jboss.mx.interceptor.ReflectedDispatcher;
   63   import org.jboss.mx.metadata.StandardMetaData;
   64   import org.jboss.mx.modelmbean.ModelMBeanConstants;
   65   import org.jboss.mx.server.InvocationContext.NullDispatcher;
   66   import org.jboss.mx.server.registry.MBeanEntry;
   67   import org.jboss.util.Strings;
   68   
   69   /**
   70    * A base MBeanInvoker class that provides common state
   71    * 
   72    * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
   73    * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>.
   74    * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
   75    * @version $Revision: 43658 $
   76    */
   77   public abstract class AbstractMBeanInvoker
   78      implements MBeanInvoker
   79   {
   80      /**
   81       * Used to propagate the MBeanEntry during the preRegister callback
   82       */
   83      static ThreadLocal preRegisterInfo = new ThreadLocal();
   84   
   85      // Attributes ----------------------------------------------------
   86   
   87      /**
   88       * The target object for this invoker.
   89       */
   90      private Object resource = null;
   91      /**
   92       * The mbean server register entry used for the TCL
   93       */
   94      protected MBeanEntry resourceEntry = null;
   95   
   96      /**
   97       * Whether this is a dynamic resource
   98       */
   99      protected boolean dynamicResource = true;
  100   
  101      /**
  102       * The metadata describing this MBean.
  103       */
  104      protected MBeanInfo info = null;
  105   
  106      protected Map attributeContextMap = new HashMap();
  107      protected Map operationContextMap = new HashMap();
  108      protected Map constructorContextMap = new HashMap();
  109   
  110      protected InvocationContext getMBeanInfoCtx = null;
  111      protected InvocationContext preRegisterCtx = null;
  112      protected InvocationContext postRegisterCtx = null;
  113      protected InvocationContext preDeregisterCtx = null;
  114      protected InvocationContext postDeregisterCtx = null;
  115   
  116      // TODO: allow to config invoker specific logs
  117      //     : multitarget mbean for invoker + log?
  118   
  119      protected Logger log = Logger.getLogger(AbstractMBeanInvoker.class);
  120   
  121      /**
  122       * The MBeanServer passed in to preRegister
  123       */
  124   
  125      private MBeanServer server;
  126   
  127      /**
  128       * Set the MBeanEntry thread local value.
  129       * @param entry - the entry that will be used on successful registration
  130       */
  131      public static void setMBeanEntry(MBeanEntry entry)
  132      {
  133         preRegisterInfo.set(entry);
  134      }
  135   
  136      /**
  137       * An accessor for the MBeanEntry thread local
  138       * @return
  139       */
  140      public static MBeanEntry getMBeanEntry()
  141      {
  142         return (MBeanEntry) preRegisterInfo.get();
  143      }
  144      // Constructors --------------------------------------------------
  145   
  146      /**
  147       * Constructs a new invoker.
  148       */
  149      public AbstractMBeanInvoker()
  150      {
  151      }
  152   
  153      /**
  154       * Constructs a new invoker with a given target resource.
  155       */
  156      public AbstractMBeanInvoker(Object resource)
  157      {
  158         this.resource = resource;
  159      }
  160   
  161      /**
  162       * Constructs an invoker with the target resource entry.
  163       * @param resourceEntry
  164       */
  165      public AbstractMBeanInvoker(MBeanEntry resourceEntry)
  166      {
  167         this.resourceEntry = resourceEntry;
  168         this.resource = resourceEntry.getResourceInstance();
  169      }
  170   
  171      // DynamicMBean implementation -----------------------------------
  172   
  173      /**
  174       * Invokes the target resource. The default invocation used by this invoker
  175       * implement sends the invocation through a stack of interceptors before
  176       * reaching the target method.
  177       * @param operationName name of the target method
  178       * @param args argumetns for the target method
  179       * @param signature signature of the target method
  180       * @throws MBeanException if the target method raised a hecked exception
  181       * @throws ReflectionException if there was an error trying to resolve or
  182       * invoke the target method
  183       * @throws RuntimeMBeanException if the target method raised an unchecked
  184       * exception
  185       */
  186      public Object invoke(String operationName, Object[] args, String[] signature)
  187         throws MBeanException, ReflectionException
  188      {
  189   
  190         // TODO:  __JBOSSMX_INVOCATION
  191   
  192         if (operationName == null)
  193            throw new ReflectionException(new IllegalArgumentException("Null operation name"));
  194         
  195         // If we have dynamic capability, check for a dynamic invocation
  196         String opName = operationName;
  197         if (dynamicResource)
  198         {
  199            int dot = operationName.lastIndexOf('.');
  200            if (dot != -1)
  201            {
  202               if (dot < operationName.length() - 1)
  203                  opName = operationName.substring(dot + 1);
  204            }
  205         }
  206         
  207         // get the server side invocation context
  208         OperationKey key = new OperationKey(opName, signature);
  209         InvocationContext ctx = (InvocationContext) operationContextMap.get(key);
  210   
  211         // if the server does not contain this context, we do not have the operation
  212         if (ctx == null)
  213         {
  214            // This is just stupid - the RI is fundamentally broken and hence the spec
  215            boolean operationExists = false;
  216            if (dynamicResource)
  217            {
  218               for (Iterator i = operationContextMap.keySet().iterator(); i.hasNext();)
  219               {
  220                  OperationKey thisKey = (OperationKey) i.next();
  221                  if (opName.equals(thisKey.keys[0]))
  222                  {
  223                     operationExists = true;
  224                     break;
  225                  }
  226               }
  227               if (operationExists)
  228                  throw new ReflectionException(new NoSuchMethodException("Unable to find operation " + operationName +
  229                     getSignatureString(signature)));
  230            }
  231            throw new ReflectionException(new IllegalArgumentException("Unable to find operation " + operationName +
  232               getSignatureString(signature)));
  233         }
  234   
  235         // create the invocation object
  236         Invocation invocation = new Invocation();
  237   
  238         // copy the server's invocation context to the invocation
  239         invocation.addContext(ctx);
  240   
  241         // set the invocation's entry point
  242         invocation.setType(InvocationContext.OP_INVOKE);
  243   
  244         // Use the passed operation
  245         invocation.setName(operationName);
  246         
  247         // set the args
  248         invocation.setArgs(args);
  249   
  250         override(invocation);
  251   
  252         ClassLoader mbeanTCL = resourceEntry.getClassLoader();
  253         final ClassLoader ccl = TCLAction.UTIL.getContextClassLoader();
  254         boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
  255         if (setCl)
  256         {
  257            TCLAction.UTIL.setContextClassLoader(mbeanTCL);
  258         }
  259   
  260         try
  261         {
  262            // the default invocation implementation will invoke each interceptor
  263            // declared in the invocation context before invoking the target method
  264            return invocation.invoke();
  265         }
  266         catch (MBeanException e)
  267         {
  268            throw e;
  269         }
  270         catch (ReflectionException e)
  271         {
  272            throw e;
  273         }
  274         catch (JMRuntimeException e)
  275         {
  276            throw e;
  277         }
  278         catch (Throwable t)
  279         {
  280            rethrowAsMBeanException(t);
  281            return null;
  282         }
  283   
  284            // TODO: should be fixed by adding invocation return value object
  285         finally
  286         {
  287            Descriptor descriptor = invocation.getDescriptor();
  288            if (descriptor != null)
  289            {
  290               ctx.setDescriptor(descriptor);
  291               if (dynamicResource && ModelMBeanConstants.OPERATION_DESCRIPTOR.equals(descriptor.getFieldValue(ModelMBeanConstants.DESCRIPTOR_TYPE)))
  292               {
  293                  ModelMBeanInfoSupport minfo = (ModelMBeanInfoSupport) info;
  294                  minfo.setDescriptor(descriptor, ModelMBeanConstants.OPERATION_DESCRIPTOR);
  295               }
  296            }
  297            invocation.setArgs(null);
  298            invocation.setDescriptor(null);
  299            invocation.setDispatcher(null);
  300   
  301            if (setCl)
  302            {
  303               TCLAction.UTIL.setContextClassLoader(ccl);
  304            }
  305         }
  306   
  307      }
  308   
  309      /**
  310       * Returns an attribte value. The request for the value is forced through a
  311       * set of interceptors before the value is returned.
  312       * @param attribute attribute name
  313       * @return attribute value
  314       * @throws AttributeNotFoundException if the requested attribute is not part
  315       * of the MBean's management interface
  316       * @throws MBeanException if retrieving the attribute value causes an
  317       * application exception
  318       * @throws ReflectionException if there was an error trying to retrieve the
  319       * attribute value
  320       */
  321      public Object getAttribute(String attribute)
  322         throws AttributeNotFoundException, MBeanException, ReflectionException
  323      {
  324         // TODO:  __JBOSSMX_INVOCATION
  325   
  326         if (attribute == null)
  327            throw new RuntimeOperationsException(new IllegalArgumentException("Cannot get null attribute"));
  328   
  329         // lookup the server side invocation context
  330         InvocationContext ctx = (InvocationContext) attributeContextMap.get(attribute);
  331   
  332         // if we don't have a server side invocation context for the attribute,
  333         // it does not exist as far as we are concerned
  334         if (ctx == null)
  335            throw new AttributeNotFoundException("not found: " + attribute);
  336   
  337         if (ctx.isReadable() == false)
  338            throw new AttributeNotFoundException("Attribute '" + attribute + "' found, but it is not readable");
  339   
  340         // create the invocation object
  341         Invocation invocation = new Invocation();
  342   
  343         // copy the server's invocation context to the invocation
  344         invocation.addContext(ctx);
  345   
  346         // indicate the invocation access point was getAttribute() method
  347         invocation.setType(InvocationContext.OP_GETATTRIBUTE);
  348         invocation.setArgs(null);
  349   
  350         override(invocation);
  351   
  352         ClassLoader mbeanTCL = resourceEntry.getClassLoader();
  353         final ClassLoader ccl = TCLAction.UTIL.getContextClassLoader();
  354         boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
  355         if (setCl)
  356         {
  357            TCLAction.UTIL.setContextClassLoader(mbeanTCL);
  358         }
  359   
  360         try
  361         {
  362            return invocation.invoke();
  363         }
  364         catch (AttributeNotFoundException e)
  365         {
  366            throw e;
  367         }
  368         catch (MBeanException e)
  369         {
  370            throw e;
  371         }
  372         catch (ReflectionException e)
  373         {
  374            throw e;
  375         }
  376         catch (JMRuntimeException e)
  377         {
  378            throw e;
  379         }
  380         catch (Throwable t)
  381         {
  382            rethrowAsMBeanException(t);
  383            return null;
  384         }
  385   
  386            // TODO: should be fixed by adding invocation return value object
  387         finally
  388         {
  389            Descriptor attrDesc = invocation.getDescriptor();
  390            ctx.setDescriptor(attrDesc);
  391            updateAttributeInfo(attrDesc);
  392   
  393            if (setCl)
  394            {
  395               TCLAction.UTIL.setContextClassLoader(ccl);
  396            }
  397         }
  398      }
  399   
  400      /**
  401       * Sets an attribute value. The operation is forced through a set of
  402       * interceptors before the new value for the attribute is set.
  403       * @param attribute new attribute value
  404       * @throws AttributeNotFoundException if the requested attribute is not part
  405       * of the MBean's management interface
  406       * @throws InvalidAttributeValueException if the attribute contains a value
  407       * not suitable for the attribute
  408       * @throws MBeanException if setting the attribute value causes an
  409       * application exception
  410       * @throws ReflectionException if there was an error trying to set the
  411       * attribute value.
  412       */
  413      public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
  414         InvalidAttributeValueException, MBeanException, ReflectionException
  415      {
  416         // TODO:  __JBOSSMX_INVOCATION
  417   
  418         if (attribute == null)
  419            throw new InvalidAttributeValueException("null attribute");
  420   
  421         // lookup the server side invocation context
  422         String name = attribute.getName();
  423         InvocationContext ctx = (InvocationContext) attributeContextMap.get(name);
  424   
  425         // if we don't have a server side invocation context for the attribute,
  426         // it does not exist as far as we are concerned
  427         if (ctx == null)
  428            throw new AttributeNotFoundException("not found: " + name);
  429         else if (ctx.isWritable() == false)
  430         {
  431            throw new AttributeNotFoundException("Attribute '" + name
  432               + "' is not writable");
  433         }
  434   
  435         // create the invocation object
  436         Invocation invocation = new Invocation();
  437   
  438         // copy the server context to the invocation
  439         invocation.addContext(ctx);
  440   
  441         // indicate the access point as setAttribute()
  442         invocation.setType(InvocationContext.OP_SETATTRIBUTE);
  443   
  444         // set the attribute value as the argument
  445         invocation.setArgs(new Object[]{attribute.getValue()});
  446   
  447         override(invocation);
  448   
  449         ClassLoader mbeanTCL = resourceEntry.getClassLoader();
  450         final ClassLoader ccl = TCLAction.UTIL.getContextClassLoader();
  451         boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
  452         if (setCl)
  453         {
  454            TCLAction.UTIL.setContextClassLoader(mbeanTCL);
  455         }
  456   
  457         try
  458         {
  459            // the default invocation implementation will invoke each interceptor
  460            // declared in the invocation context before invoking the target method
  461            invocation.invoke();
  462         }
  463         catch (AttributeNotFoundException e)
  464         {
  465            throw e;
  466         }
  467         catch (InvalidAttributeValueException e)
  468         {
  469            throw e;
  470         }
  471         catch (MBeanException e)
  472         {
  473            throw e;
  474         }
  475         catch (ReflectionException e)
  476         {
  477            throw e;
  478         }
  479         catch (JMRuntimeException e)
  480         {
  481            throw e;
  482         }
  483         catch (Throwable t)
  484         {
  485            rethrowAsMBeanException(t);
  486         }
  487   
  488            // TODO: should be fixed by adding invocation return value object
  489         finally
  490         {
  491            /* Obtain the updated attribute descriptor and propagate to the
  492            invocation context and ModelMBeanInfo. The latter is required in
  493            order for getMBeanInfo() to show an updated view.
  494            */
  495            Descriptor attrDesc = invocation.getDescriptor();
  496            ctx.setDescriptor(attrDesc);
  497            updateAttributeInfo(attrDesc);
  498   
  499            if (setCl)
  500            {
  501               TCLAction.UTIL.setContextClassLoader(ccl);
  502            }
  503         }
  504      }
  505   
  506      public MBeanInfo getMBeanInfo()
  507      {
  508         // create the invocation object
  509         Invocation invocation = new Invocation(getMBeanInfoCtx);
  510   
  511         // set the invocation's access point as getMBeanInfo()
  512         invocation.setType(InvocationContext.OP_GETMBEANINFO);
  513   
  514         if (resourceEntry == null)
  515            resourceEntry = getMBeanEntry();
  516         ClassLoader mbeanTCL = resourceEntry.getClassLoader();
  517         final ClassLoader ccl = TCLAction.UTIL.getContextClassLoader();
  518         boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
  519         if (setCl)
  520         {
  521            TCLAction.UTIL.setContextClassLoader(mbeanTCL);
  522         }
  523   
  524         try
  525         {
  526            MBeanInfo info = (MBeanInfo) invocation.invoke();
  527            return info;
  528         }
  529         catch (JMRuntimeException e)
  530         {
  531            throw e;
  532         }
  533         catch (Throwable t)
  534         {
  535            rethrowAsRuntimeMBeanException(t);
  536            return null;
  537         }
  538         finally
  539         {
  540            if (setCl)
  541            {
  542               TCLAction.UTIL.setContextClassLoader(ccl);
  543            }
  544         }
  545      }
  546   
  547      public AttributeList getAttributes(java.lang.String[] attributes)
  548      {
  549         if (attributes == null)
  550            throw new IllegalArgumentException("null array");
  551   
  552         AttributeList list = new AttributeList();
  553   
  554         for (int i = 0; i < attributes.length; ++i)
  555         {
  556            try
  557            {
  558               list.add(new Attribute(attributes[i], getAttribute(attributes[i])));
  559            }
  560            catch (Throwable ignored)
  561            {
  562               // if the attribute could not be retrieved, skip it
  563            }
  564         }
  565   
  566         return list;
  567      }
  568   
  569      public AttributeList setAttributes(AttributeList attributes)
  570      {
  571         if (attributes == null)
  572            throw new IllegalArgumentException("null list");
  573   
  574         AttributeList results = new AttributeList();
  575         Iterator it = attributes.iterator();
  576   
  577         while (it.hasNext())
  578         {
  579            Attribute attr = (Attribute) it.next();
  580            try
  581            {
  582               setAttribute(attr);
  583               results.add(attr);
  584            }
  585            catch (Throwable ignored)
  586            {
  587               // if unable to set the attribute, skip it
  588               if (log.isTraceEnabled())
  589                  log.trace("Unhandled setAttribute() for attribute: " + attr.getName(), ignored);
  590            }
  591         }
  592   
  593         return results;
  594      }
  595   
  596   
  597      // MBeanRegistration implementation ------------------------------
  598   
  599      /**
  600       * Initializes this invoker. At the registration time we can be sure that all
  601       * of the metadata is available and initialize the invoker and cache the data
  602       * accordingly.   <p>
  603       *
  604       * Subclasses that override the <tt>preRegister</tt> method must make sure
  605       * they call <tt>super.preRegister()</tt> in their implementation to ensure
  606       * proper initialization of the invoker.
  607       */
  608      public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception
  609      {
  610         this.resourceEntry = (MBeanEntry) preRegisterInfo.get();
  611         this.server = server;
  612   
  613         ObjectName mbeanName = null;
  614         Descriptor mbeanDescriptor = null;
  615         if( info instanceof ModelMBeanInfo )
  616         {
  617            ModelMBeanInfo minfo = (ModelMBeanInfo) info;
  618            try
  619            {
  620               mbeanDescriptor = minfo.getDescriptor("",
  621                              ModelMBeanConstants.MBEAN_DESCRIPTOR);
  622               String type = (String) mbeanDescriptor.getFieldValue(
  623                  ModelMBeanConstants.MBEAN_SERVER_INJECTION_TYPE);
  624               if( type != null )
  625               {
  626                  inject(ModelMBeanConstants.MBEAN_SERVER_INJECTION_TYPE,
  627                     type, MBeanServer.class, getServer());
  628               }
  629            }
  630            catch (MBeanException e)
  631            {
  632               log.warn("Failed to obtain descriptor: "+ModelMBeanConstants.MBEAN_DESCRIPTOR, e);
  633            }
  634   
  635         }
  636   
  637         ClassLoader mbeanTCL = resourceEntry.getClassLoader();
  638         final ClassLoader ccl = TCLAction.UTIL.getContextClassLoader();
  639         boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
  640         if (setCl)
  641         {
  642            TCLAction.UTIL.setContextClassLoader(mbeanTCL);
  643         }
  644   
  645         try
  646         {
  647            initAttributeContexts(info.getAttributes());
  648   
  649            initOperationContexts(info.getOperations());
  650   
  651            if (resource != null)
  652               initDispatchers();
  653   
  654            mbeanName = invokePreRegister(server, name);
  655            if( mbeanDescriptor != null )
  656            {
  657               Object value = mbeanDescriptor.getFieldValue(
  658               ModelMBeanConstants.OBJECT_NAME_INJECTION_TYPE);
  659               String type = (String) value;
  660               if( type != null )
  661               {
  662                  inject(ModelMBeanConstants.OBJECT_NAME_INJECTION_TYPE,
  663                     type, ObjectName.class, mbeanName);
  664               }
  665            }
  666         }
  667         finally
  668         {
  669            if (setCl)
  670            {
  671               TCLAction.UTIL.setContextClassLoader(ccl);
  672            }
  673         }
  674         return mbeanName;
  675      }
  676   
  677      /**
  678       */
  679      public void postRegister(Boolean registrationSuccessful)
  680      {
  681         invokePostRegister(registrationSuccessful);
  682      }
  683   
  684      /**
  685       */
  686      public void preDeregister() throws Exception
  687      {
  688         invokePreDeregister();
  689      }
  690   
  691      /**
  692       */
  693      public void postDeregister()
  694      {
  695         invokePostDeregister();
  696         this.server = null;
  697      }
  698   
  699   
  700      // NotificationEmitter implementation ------------------------
  701   
  702      public void addNotificationListener(NotificationListener listener,
  703         NotificationFilter filter, Object handback)
  704      {
  705         addNotificationListenerToResource(listener, filter, handback);
  706      }
  707   
  708      protected void addNotificationListenerToResource(NotificationListener listener, NotificationFilter filter, Object handback)
  709      {
  710         if (resource instanceof NotificationBroadcaster)
  711         {
  712            ((NotificationBroadcaster) resource).addNotificationListener(listener, filter, handback);
  713         }
  714         else
  715         {
  716            throw new RuntimeMBeanException(new IllegalArgumentException("Target XXX is not a notification broadcaster"
  717   
  718               // FIXME: add the XXX object name, store from registration
  719            ));
  720         }
  721      }
  722   
  723      public void removeNotificationListener(NotificationListener listener)
  724         throws ListenerNotFoundException
  725      {
  726         removeNotificationListenerFromResource(listener);
  727      }
  728   
  729      protected void removeNotificationListenerFromResource(NotificationListener listener)
  730         throws ListenerNotFoundException
  731      {
  732         if (resource instanceof NotificationBroadcaster)
  733         {
  734            ((NotificationBroadcaster) resource).removeNotificationListener(listener);
  735         }
  736         else
  737         {
  738            throw new RuntimeMBeanException(new IllegalArgumentException("Target XXX is not a notification broadcaster"
  739   
  740               // FIXME: add the XXX object name, store from registration
  741            ));
  742         }
  743      }
  744   
  745      public void removeNotificationListener(NotificationListener listener,
  746         NotificationFilter filter,
  747         Object handback)
  748         throws ListenerNotFoundException
  749      {
  750         removeNotificationListenerFromResource(listener, filter, handback);
  751      }
  752   
  753      protected void removeNotificationListenerFromResource(NotificationListener listener,
  754         NotificationFilter filter,
  755         Object handback)
  756         throws ListenerNotFoundException
  757      {
  758         if (resource instanceof NotificationEmitter)
  759         {
  760            ((NotificationEmitter) resource).removeNotificationListener(listener, filter, handback);
  761         }
  762         else if (resource instanceof NotificationBroadcaster)
  763         {
  764            //JGH NOTE: looks like a listener against the MBeanServer is
  765            //wrapped as a XMBean which has a broadcaster that is an NotificationEmitter
  766            //but this resource target is a NotificationBroadcaster, in which case,
  767            //w/o this .. you'll get a resource failure below
  768            removeNotificationListener(listener);
  769         }
  770         else
  771         {
  772            throw new RuntimeMBeanException(new IllegalArgumentException("Target XXX is not a notification emitter"
  773   
  774               // FIXME: add the XXX object name, store from registration
  775            ));
  776         }
  777      }
  778   
  779      public MBeanNotificationInfo[] getNotificationInfo()
  780      {
  781         return getNotificationInfoFromResource();
  782      }
  783   
  784      protected MBeanNotificationInfo[] getNotificationInfoFromResource()
  785      {
  786         if (resource instanceof NotificationBroadcaster)
  787         {
  788            return ((NotificationBroadcaster) resource).getNotificationInfo();
  789         }
  790         else
  791            return new MBeanNotificationInfo[]{};
  792      }
  793   
  794   
  795      // MBeanInvoker implementation -----------------------------------
  796   
  797      public MBeanInfo getMetaData()
  798      {
  799         return info;
  800      }
  801      
  802      public Object getResource()
  803      {
  804         return resource;
  805      }
  806   
  807      /**
  808       * Sets the XMBean resource and optionally allows the resource to interact
  809       * with the jmx microkernel via the following injection points:
  810       * #ModelMBeanConstants.MBEAN_SERVER_INJECTION_TYPE
  811       * #ModelMBeanConstants.MBEAN_INFO_INJECTION_TYPE
  812       * #ModelMBeanConstants.OBJECT_NAME_INJECTION_TYPE
  813       * @param resource - the model mbean resource
  814       */
  815      public void setResource(Object resource)
  816      {
  817         this.resource = resource;
  818      }
  819   
  820      public ObjectName getObjectName()
  821      {
  822         if (resourceEntry == null)
  823            return null;
  824         else
  825            return resourceEntry.getObjectName();
  826      }
  827   
  828      public void updateAttributeInfo(Descriptor attrDesc) throws MBeanException
  829      {
  830         ModelMBeanInfoSupport minfo = (ModelMBeanInfoSupport) info;
  831         minfo.setDescriptor(attrDesc, ModelMBeanConstants.ATTRIBUTE_DESCRIPTOR);
  832      }
  833      
  834      /**
  835       * Add dynamically an operation interceptor, first in the chain.
  836       */
  837      public void addOperationInterceptor(Interceptor interceptor)
  838      {
  839         if (operationContextMap != null && interceptor != null)
  840         {
  841            // Go through all the operation InvocationContext and add the interceptor
  842            for (Iterator it = operationContextMap.entrySet().iterator(); it.hasNext();)
  843            {
  844               Map.Entry entry = (Map.Entry) it.next();
  845      
  846               InvocationContext ctx = (InvocationContext) entry.getValue();
  847               List list = ctx.getInterceptors();
  848   
  849               // to make the interceptor list update atomic, make a new ArrayList,
  850               // add the new interceptor first and copy over the old ones,
  851               // then update the context
  852               List newList = new ArrayList();
  853               newList.add(interceptor);
  854               
  855               if (list != null)
  856               {
  857                  newList.addAll(list);
  858               }
  859               
  860               ctx.setInterceptors(newList);
  861            }         
  862         }
  863      }
  864      
  865      /** 
  866       * Remove the specified operation interceptor 
  867       */
  868      public void removeOperationInterceptor(Interceptor interceptor)
  869      {
  870         if (operationContextMap != null && interceptor != null)
  871         {
  872            // Go through all the operation InvocationContext and remove the interceptor
  873            for (Iterator it = operationContextMap.entrySet().iterator(); it.hasNext();)
  874            {
  875               Map.Entry entry = (Map.Entry) it.next();
  876   
  877               InvocationContext ctx = (InvocationContext) entry.getValue();
  878               List list = ctx.getInterceptors();
  879               
  880               // to make the interceptor list update atomic, make a copy of the list
  881               // remove the interceptor (if found), then update the context
  882               if (list != null)
  883               {
  884                  List newList = new ArrayList(list);
  885   
  886                  // this should probably work, whether or not equals() is implemented
  887                  // it'll remove the first occurence
  888                  newList.remove(interceptor);
  889                  
  890                  ctx.setInterceptors(newList);
  891               }
  892            }
  893         }
  894      }
  895      
  896      // Other Public Methods ------------------------------------------
  897      
  898      public void suspend()
  899      {
  900      }
  901   
  902      public void suspend(long wait) throws TimeoutException
  903      {
  904      }
  905   
  906      public void suspend(boolean force)
  907      {
  908      }
  909   
  910      public boolean isSuspended()
  911      {
  912         return false;
  913      }
  914   
  915      public void setInvocationTimeout(long time)
  916      {
  917      }
  918   
  919      public long getInvocationTimeout()
  920      {
  921         return 0l;
  922      }
  923   
  924      public void resume()
  925      {
  926      }
  927   
  928      public MBeanServer getServer()
  929      {
  930         return server;
  931      }
  932   
  933      // Protected -----------------------------------------------------
  934   
  935      /**
  936       * Inject context from the xmbean layer to the resource
  937       * @param type - the type of injection 
  938       * @param name - the setter method name of the resource
  939       * @param argType - the injection data type
  940       * @param value - the injection data value to pass to the setter
  941       */ 
  942      protected void inject(String type, String name, Class argType, Object value)
  943      {
  944         try
  945         {
  946            Class resClass = resource.getClass();
  947            Class[] sig = {argType};
  948            Method setter = resClass.getMethod(name, sig);
  949            Object[] args = {value};
  950            setter.invoke(resource, args);
  951         }
  952         catch(NoSuchMethodException e)
  953         {
  954            log.debug("Setter not found: "+name+"("+argType+")", e);
  955         }
  956         catch(Exception e)
  957         {
  958            log.warn("Failed to inject type: "+type+" using setter: "+name, e);
  959         }
  960      }
  961   
  962      protected ObjectName invokePreRegister(MBeanServer server, ObjectName name)
  963         throws Exception
  964      {
  965         if (resource instanceof MBeanRegistration)
  966            return ((MBeanRegistration) resource).preRegister(server, name);
  967   
  968         return name;
  969      }
  970   
  971      protected void invokePostRegister(Boolean b)
  972      {
  973         if (resource instanceof MBeanRegistration)
  974            ((MBeanRegistration) resource).postRegister(b);
  975      }
  976   
  977      protected void invokePreDeregister() throws Exception
  978      {
  979         if (resource instanceof MBeanRegistration)
  980            ((MBeanRegistration) resource).preDeregister();
  981      }
  982   
  983      protected void invokePostDeregister()
  984      {
  985         if (resource instanceof MBeanRegistration)
  986            ((MBeanRegistration) resource).postDeregister();
  987      }
  988   
  989      protected void initAttributeContexts(MBeanAttributeInfo[] attributes)
  990      {
  991         // create invocation contexts for attributes
  992         for (int i = 0; i < attributes.length; ++i)
  993         {
  994            InvocationContext ctx = new InvocationContext();
  995   
  996            // fill in some default values, the attribute name
  997            ctx.setName(attributes[i].getName());
  998   
  999            ctx.setAttributeType(attributes[i].getType());
 1000   
 1001            // set myself as the invoker
 1002            ctx.setInvoker(this);
 1003   
 1004            //ctx.add(InvocationContext.ATTRIBUTE_ACCESS, getAccessCode(attributes[i]));
 1005   
 1006            // store
 1007            attributeContextMap.put(attributes[i].getName(), ctx);
 1008         }
 1009         if (log.isTraceEnabled())
 1010            log.trace(getObjectName() + " configured attribute contexts: " + operationContextMap);      
 1011      }
 1012   
 1013      protected void initOperationContexts(MBeanOperationInfo[] operations)
 1014      {
 1015         // create invocation contexts for operations
 1016         for (int i = 0; i < operations.length; ++i)
 1017         {
 1018            InvocationContext ctx = new InvocationContext();
 1019   
 1020            // extract operation name + signature
 1021            String opName = operations[i].getName();
 1022            MBeanParameterInfo[] signature = operations[i].getSignature();
 1023            String returnType = operations[i].getReturnType();
 1024   
 1025            // name is unchanged, fill in the context
 1026            ctx.setName(opName);
 1027   
 1028            // signature doesn't change..
 1029            ctx.setSignature(signature);
 1030   
 1031            // return type
 1032            ctx.setReturnType(returnType);
 1033            
 1034            // set myself as the invoker
 1035            ctx.setInvoker(this);
 1036   
 1037            // add impact as part of ctx map (rarely accessed information)
 1038            //ctx.add(InvocationContext.OPERATION_IMPACT, operations[i].getImpact());
 1039   
 1040            // create an operation key consisting of the name + signature
 1041            // (required for overloaded operations)
 1042            OperationKey opKey = new OperationKey(opName, signature);
 1043   
 1044            // store
 1045            operationContextMap.put(opKey, ctx);
 1046         }
 1047         
 1048         if (log.isTraceEnabled())
 1049            log.trace(getObjectName() + " configured operation contexts: " + operationContextMap);         
 1050      }
 1051   
 1052      protected void initDispatchers()
 1053      {
 1054         boolean trace = log.isTraceEnabled();
 1055         
 1056         // locate the resource class to receive the invocations
 1057         Class clazz = null;
 1058         if (resource != null)
 1059         {
 1060            clazz = resource.getClass();
 1061            
 1062            // JBAS-1704, if the target class is *not* public, look for
 1063            // an exposed MBean interface, if one exists.
 1064            // This should be checking if we are dealing with a standard
 1065            // mbean (but not a standard mbean deployed as a model mbean)
 1066            // but it doesn't look convenient from this baseclass.
 1067            if (Modifier.isPublic(clazz.getModifiers()) == false)
 1068            {
 1069               clazz = StandardMetaData.findStandardInterface(clazz);
 1070            }
 1071         }
 1072         
 1073         // map the Methods on the target resource for easy access
 1074         MethodMapper mmap = new MethodMapper(clazz);
 1075         if (trace)
 1076            log.trace(getObjectName() + " " + clazz + " map=" + mmap);
 1077         
 1078         MBeanOperationInfo[] operations = info.getOperations();
 1079         
 1080         // Set the dispatchers for the operations
 1081         for (int i = 0; i < operations.length; ++i)
 1082         {
 1083            MBeanOperationInfo op = operations[i];
 1084            OperationKey opKey = new OperationKey(op.getName(), op.getSignature());
 1085            InvocationContext ctx = (InvocationContext) operationContextMap.get(opKey);
 1086   
 1087            Interceptor dispatcher = ctx.getDispatcher();
 1088            
 1089            // Reconfigure if we have a Null or Reflected dispatcher
 1090            if (dispatcher instanceof NullDispatcher || (dispatcher instanceof ReflectedDispatcher))
 1091            {
 1092               Object target = null;
 1093               dispatcher = null;
 1094               Method m = mmap.lookupOperation(op);
 1095               if (m == null)
 1096               {
 1097                  // Look for an method on the model mbean
 1098                  m = MethodMapper.lookupOperation(op, this);
 1099                  if (m != null)
 1100                  {
 1101                     // operation found on the 'this' invoker
 1102                     target = this;
 1103                     dispatcher = new ReflectedDispatcher(m, dynamicResource);
 1104                  }
 1105                  else
 1106                  {
 1107                     // operation not found, use late binding
 1108                     // What is this late binding attempt and should there be a warning?
 1109                     dispatcher = new ReflectedDispatcher(dynamicResource);
 1110                  }
 1111               }
 1112               else
 1113               {
 1114                  // operation found on the resource
 1115                  target = resource;
 1116                  dispatcher = new ReflectedDispatcher(m, dynamicResource);
 1117               }
 1118               if (trace)
 1119                  log.trace(getObjectName() + " will dispatch op=" + opKey + 
 1120                     " to " + Strings.defaultToString(target) +
 1121                     " method= " + m);            
 1122               ctx.setTarget(target);
 1123               ctx.setDispatcher(dispatcher);
 1124            }
 1125         }
 1126   
 1127         // Set the dispatchers for the attributes with getters/setters
 1128         MBeanAttributeInfo[] attributes = info.getAttributes();
 1129         for (int i = 0; i < attributes.length; ++i)
 1130         {
 1131            MBeanAttributeInfo attribute = attributes[i];
 1132            String name = attribute.getName();
 1133            InvocationContext ctx = (InvocationContext) attributeContextMap.get(name);
 1134   
 1135            Method getter = mmap.lookupGetter(attribute);
 1136            Method setter = mmap.lookupSetter(attribute);
 1137            ctx.setDispatcher(new AttributeDispatcher(getter, setter, dynamicResource));
 1138            ctx.setTarget(resource);
 1139         }
 1140      }
 1141   
 1142      /**
 1143       * Placeholder to allow subclasses to override the invocation
 1144       * @param invocation the invocation
 1145       * @throws MBeanException for any error
 1146       */
 1147      protected void override(Invocation invocation) throws MBeanException
 1148      {
 1149      }
 1150   
 1151      protected String getSignatureString(String[] signature)
 1152      {
 1153         if (signature == null)
 1154            return "()";
 1155         if (signature.length == 0)
 1156            return "()";
 1157   
 1158         StringBuffer sbuf = new StringBuffer(512);
 1159   
 1160         sbuf.append("(");
 1161         for (int i = 0; i < signature.length - 1; ++i)
 1162         {
 1163            sbuf.append(signature[i]);
 1164            sbuf.append(",");
 1165         }
 1166         sbuf.append(signature[signature.length - 1]);
 1167         sbuf.append(")");
 1168   
 1169         return sbuf.toString();
 1170      }
 1171   
 1172   
 1173      // Inner classes -------------------------------------------------
 1174      protected final class OperationKey
 1175      {
 1176         String[] keys = null;
 1177         int hash = 0;
 1178   
 1179         public OperationKey(final String name, final String type)
 1180         {
 1181            if (type != null)
 1182            {
 1183               keys = new String[2];
 1184   
 1185               keys[0] = name;
 1186               keys[1] = type;
 1187   
 1188               hash = name.hashCode();
 1189            }
 1190   
 1191            else
 1192            {
 1193               keys = new String[]{name};
 1194               hash = name.hashCode();
 1195            }
 1196         }
 1197   
 1198         public OperationKey(final String name, final String[] signature)
 1199         {
 1200            if (signature != null)
 1201            {
 1202               keys = new String[signature.length + 1];
 1203   
 1204               keys[0] = name;
 1205   
 1206               System.arraycopy(signature, 0, keys, 1, signature.length);
 1207   
 1208               hash = name.hashCode();
 1209            }
 1210   
 1211            else
 1212            {
 1213               keys = new String[]{name};
 1214               hash = name.hashCode();
 1215            }
 1216         }
 1217   
 1218         public OperationKey(String name, MBeanParameterInfo[] signature)
 1219         {
 1220            if (signature == null)
 1221               signature = new MBeanParameterInfo[0];
 1222   
 1223            keys = new String[signature.length + 1];
 1224   
 1225            keys[0] = name;
 1226   
 1227            for (int i = 0; i < signature.length; ++i)
 1228            {
 1229               keys[i + 1] = signature[i].getType();
 1230            }
 1231   
 1232            hash = name.hashCode();
 1233         }
 1234   
 1235         public OperationKey(MBeanOperationInfo info)
 1236         {
 1237            this(info.getName(), info.getSignature());
 1238         }
 1239   
 1240         public int hashCode()
 1241         {
 1242            return hash;
 1243         }
 1244   
 1245         public boolean equals(Object o)
 1246         {
 1247            OperationKey target = (OperationKey) o;
 1248   
 1249            if (target.keys.length != keys.length)
 1250               return false;
 1251   
 1252            for (int i = 0; i < keys.length; ++i)
 1253            {
 1254               if (!(keys[i].equals(target.keys[i])))
 1255                  return false;
 1256            }
 1257   
 1258            return true;
 1259         }
 1260   
 1261         public String toString()
 1262         {
 1263            StringBuffer buffer = new StringBuffer(50);
 1264            buffer.append(keys[0]).append("(");
 1265   
 1266            for (int i = 1; i < keys.length - 1; ++i)
 1267            {
 1268               buffer.append(keys[i]).append(',');
 1269            }
 1270   
 1271            if (keys.length > 1)
 1272               buffer.append(keys[keys.length - 1]);
 1273            buffer.append(")");
 1274            return buffer.toString();
 1275         }
 1276      }
 1277   
 1278      private void rethrowAsMBeanException(Throwable t) throws MBeanException
 1279      {
 1280         if (t instanceof RuntimeException)
 1281            throw new RuntimeMBeanException((RuntimeException) t);
 1282         else if (t instanceof Error)
 1283            throw new RuntimeErrorException((Error) t);
 1284         else
 1285            throw new MBeanException((Exception) t);
 1286      }
 1287   
 1288      private void rethrowAsRuntimeMBeanException(Throwable t)
 1289      {
 1290         if (t instanceof RuntimeException)
 1291            throw new RuntimeMBeanException((RuntimeException) t);
 1292         else if (t instanceof Error)
 1293            throw new RuntimeErrorException((Error) t);
 1294         else
 1295            throw new RuntimeMBeanException(new RuntimeException("Unhandled exception", t));
 1296      }
 1297   }

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