Save This Page
Home » jboss-5.0.0.CR1-src » org.jboss.mx » server » registry » [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.registry;
   23   
   24   import java.util.ArrayList;
   25   import java.util.Iterator;
   26   import java.util.List;
   27   import java.util.Map;
   28   import java.util.Vector;
   29   import javax.management.Descriptor;
   30   import javax.management.DynamicMBean;
   31   import javax.management.InstanceAlreadyExistsException;
   32   import javax.management.InstanceNotFoundException;
   33   import javax.management.MBeanException;
   34   import javax.management.MBeanInfo;
   35   import javax.management.MBeanRegistration;
   36   import javax.management.MBeanRegistrationException;
   37   import javax.management.MBeanServer;
   38   import javax.management.MBeanServerDelegate;
   39   import javax.management.MBeanServerNotification;
   40   import javax.management.MalformedObjectNameException;
   41   import javax.management.NotCompliantMBeanException;
   42   import javax.management.ObjectInstance;
   43   import javax.management.ObjectName;
   44   import javax.management.ReflectionException;
   45   import javax.management.RuntimeErrorException;
   46   import javax.management.RuntimeMBeanException;
   47   import javax.management.RuntimeOperationsException;
   48   import javax.management.loading.ClassLoaderRepository;
   49   import javax.management.modelmbean.ModelMBeanInfo;
   50   import javax.management.modelmbean.RequiredModelMBean;
   51   
   52   import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
   53   import EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
   54   
   55   import org.jboss.classloading.spi.RealClassLoader;
   56   import org.jboss.logging.Logger;
   57   import org.jboss.mx.loading.LoaderRepository;
   58   import org.jboss.mx.loading.RepositoryClassLoader;
   59   import org.jboss.mx.metadata.MBeanCapability;
   60   import org.jboss.mx.modelmbean.ModelMBeanConstants;
   61   import org.jboss.mx.modelmbean.RequiredModelMBeanInvoker;
   62   import org.jboss.mx.modelmbean.XMBean;
   63   import org.jboss.mx.modelmbean.XMBeanConstants;
   64   import org.jboss.mx.server.AbstractMBeanInvoker;
   65   import org.jboss.mx.server.MBeanInvoker;
   66   import org.jboss.mx.server.RawDynamicInvoker;
   67   import org.jboss.mx.server.ServerConfig;
   68   import org.jboss.mx.server.ServerObjectInstance;
   69   import org.jboss.mx.util.ObjectNamePatternHelper;
   70   import org.jboss.mx.util.ObjectNamePatternHelper.PropertyPattern;
   71   import org.jboss.util.NestedRuntimeException;
   72   
   73   /**
   74    * The registry for object name - object reference mapping in the
   75    * MBean server.
   76    * <p>
   77    * The implementation of this class affects the invocation speed
   78    * directly, please check any changes for performance.
   79    *
   80    * @todo JMI_DOMAIN isn't very protected
   81    *
   82    * @see org.jboss.mx.server.registry.MBeanRegistry
   83    *
   84    * @author  <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
   85    * @author  <a href="mailto:trevor@protocool.com">Trevor Squires</a>.
   86    * @author  <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
   87    * @author  <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>.
   88    * @author  <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
   89    *
   90    * @version $Revision: 64035 $
   91    */
   92   public class BasicMBeanRegistry
   93      implements MBeanRegistry
   94   {
   95      // Constants -----------------------------------------------------
   96   
   97      /** The server config */
   98      private static ServerConfig serverConfig = ServerConfig.getInstance();
   99   
  100      /** The default domain */
  101      private static String JMI_DOMAIN = serverConfig.getJMIDomain();
  102   
  103      // Attributes ----------------------------------------------------
  104   
  105      /**
  106       * A map of domain name to another map containing object name canonical
  107       * key properties to registry entries.
  108       * domain -> canonicalKeyProperties -> MBeanEntry
  109       */
  110      private Map domainMap = new ConcurrentReaderHashMap();
  111   
  112      /**
  113       * The default domain for this registry
  114       */
  115      private String defaultDomain;
  116   
  117      /**
  118       * The MBeanServer for which we are the registry.
  119       */
  120      private MBeanServer server;
  121   
  122      /**
  123       * The loader repository for loading classes
  124       */
  125      private LoaderRepository loaderRepository;
  126   
  127      /**
  128       * Sequence number for the MBean server registration notifications.
  129       */
  130      protected final SynchronizedLong registrationNotificationSequence = new SynchronizedLong (1);
  131   
  132      /**
  133       * Sequence number for the MBean server unregistration notifications.
  134       */
  135      protected final SynchronizedLong unregistrationNotificationSequence = new SynchronizedLong (1);
  136   
  137      /**
  138       * Direct reference to the mandatory MBean server delegate MBean.
  139       */
  140      protected MBeanServerDelegate delegate;
  141   
  142      protected Vector fMbInfosToStore;
  143      private ObjectName mbeanInfoService;
  144   
  145   
  146      // Static --------------------------------------------------------
  147   
  148      /**
  149       * The logger
  150       */
  151      protected static Logger log = Logger.getLogger(BasicMBeanRegistry.class);
  152   
  153   
  154      // Constructors --------------------------------------------------
  155   
  156      /**
  157       * Constructs a new BasicMBeanRegistry.<p>
  158       */
  159      public BasicMBeanRegistry(MBeanServer server, String defaultDomain, ClassLoaderRepository clr)
  160      {
  161         // Store the context
  162         this.server = server;
  163         this.defaultDomain = defaultDomain;
  164   
  165         try
  166         {
  167            loaderRepository = (LoaderRepository) clr;
  168            mbeanInfoService = new ObjectName("user:service=MBeanInfoDB");
  169         }
  170         catch (Exception e)
  171         {
  172            throw new NestedRuntimeException("Error instantiating registry", e);
  173         }
  174      }
  175   
  176   
  177      // MBeanRegistry Implementation ----------------------------------
  178   
  179      public ObjectInstance registerMBean(Object object, ObjectName name, Map valueMap)
  180         throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException
  181      {
  182         ObjectName regName         = name;
  183         boolean registrationDone   = true;
  184         boolean invokedPreRegister = false;
  185         String magicToken          = null;
  186         MBeanInvoker invoker       = null;
  187   
  188         if (object == null)
  189            throw new RuntimeOperationsException(
  190                  new IllegalArgumentException("Attempting to register null object"));
  191   
  192         // get mbean type, dynamic or standard
  193         MBeanCapability mbcap = MBeanCapability.of(object.getClass());
  194   
  195         try
  196         {
  197   
  198            if (valueMap != null)
  199               magicToken = (String) valueMap.get(JMI_DOMAIN);
  200   
  201            // TODO: allow custom factory for diff invoker types
  202            int mbeanType = mbcap.getMBeanType();
  203            if (mbeanType == MBeanCapability.STANDARD_MBEAN)
  204            {
  205               invoker = new XMBean(object, XMBeanConstants.STANDARD_MBEAN);
  206            }
  207            else if (object instanceof MBeanInvoker)
  208            {
  209               invoker = (MBeanInvoker)object;
  210            }
  211            else if (mbeanType == MBeanCapability.DYNAMIC_MBEAN)
  212            {
  213               if( object instanceof RequiredModelMBean )
  214                  invoker = new RequiredModelMBeanInvoker((DynamicMBean)object);
  215               else
  216                  invoker = new RawDynamicInvoker((DynamicMBean)object);
  217            }
  218   
  219            // Perform the pregistration
  220            MBeanEntry entry = new MBeanEntry(regName, invoker, object, valueMap);
  221            AbstractMBeanInvoker.setMBeanEntry(entry);
  222            regName = invokePreRegister(invoker, regName, magicToken);
  223            invokedPreRegister = true;
  224   
  225            try
  226            {
  227               MBeanInfo info = invoker.getMBeanInfo();
  228               verifyMBeanInfo(info, name);
  229               entry.setResourceClassName(info.getClassName());
  230   
  231               // Register the mbean
  232   
  233               // Update the registered name to the final value
  234               entry.setObjectName(regName);
  235   
  236               add(entry);
  237   
  238               try
  239               {
  240                  // Add the classloader to the repository
  241                  if (object instanceof ClassLoader)
  242                     registerClassLoader((ClassLoader)object);
  243   
  244                  try
  245                  {
  246                     if (delegate != null)
  247                        sendRegistrationNotification (regName);
  248                     else if (serverConfig.getMBeanServerDelegateName().equals(name))
  249                        delegate = (MBeanServerDelegate) object;
  250   
  251                     ServerObjectInstance serverObjInst = new ServerObjectInstance
  252                           (regName, entry.getResourceClassName(), delegate.getMBeanServerId());
  253   
  254                     persistIfRequired(invoker.getMBeanInfo(), regName);
  255   
  256                     return serverObjInst;
  257   
  258                  }
  259                  catch (Throwable t)
  260                  {
  261                     // Problem, remove a classloader from the repository
  262                     if (object instanceof ClassLoader)
  263                        loaderRepository.removeClassLoader((ClassLoader)object);
  264   
  265                     throw t;
  266                  }
  267               }
  268               catch (Throwable t)
  269               {
  270                  // Problem, remove the mbean from the registry
  271                  remove(regName);
  272                  throw t;
  273               }
  274            }
  275            // Throw for null MBeanInfo
  276            catch (NotCompliantMBeanException e)
  277            {
  278               throw e;
  279            }
  280            // Thrown by the registry
  281            catch (InstanceAlreadyExistsException e)
  282            {
  283               throw e;
  284            }
  285            catch (Throwable t)
  286            {
  287               // Something is broken
  288               log.error("Unexpected Exception:", t);
  289               throw t;
  290            }
  291         }
  292         catch (NotCompliantMBeanException e)
  293         {
  294            registrationDone = false;
  295            throw e;
  296         }
  297         catch (InstanceAlreadyExistsException e)
  298         {
  299            // It was already registered
  300            registrationDone = false;
  301            throw e;
  302         }
  303         catch (MBeanRegistrationException e)
  304         {
  305            // The MBean cancelled the registration
  306            registrationDone = false;
  307            log.warn(e.toString());
  308            throw e;
  309         }
  310         catch (RuntimeOperationsException e)
  311         {
  312            // There was a problem with one the arguments
  313            registrationDone = false;
  314            throw e;
  315         }
  316         catch (Exception ex)
  317         {
  318            // any other exception is mapped to NotCompliantMBeanException
  319            registrationDone = false;
  320            NotCompliantMBeanException ncex = new NotCompliantMBeanException("Cannot register MBean: " + name);
  321            ncex.initCause(ex);
  322            throw ncex;
  323         }
  324         catch (Throwable t)
  325         {
  326            // Some other error
  327            log.error("Cannot register MBean", t);
  328            registrationDone = false;
  329            return null;
  330         }
  331         finally
  332         {
  333            // Tell the MBean the result of the registration
  334            if (invoker != null)
  335            {
  336               try
  337               {
  338                  invoker.postRegister(new Boolean(registrationDone));
  339               }
  340               catch(Exception e)
  341               {
  342                  // Only throw this if preRegister succeeded
  343                  if( invokedPreRegister == true )
  344                  {
  345                     if( e instanceof RuntimeException )
  346                        throw new RuntimeMBeanException((RuntimeException) e);
  347                     else
  348                        throw new MBeanRegistrationException(e);
  349                  }
  350               }
  351            }
  352            AbstractMBeanInvoker.setMBeanEntry(null);
  353         }
  354       }
  355   
  356      /**
  357       * Verifies the MBeanInfo and throws an exception if something is wrong.
  358       * @param info a MBeanInfo
  359       * @param name a ObjectName
  360       * @throws NotCompliantMBeanException when something is wrong with the MBean info
  361       */
  362      private void verifyMBeanInfo(MBeanInfo info, ObjectName name)
  363              throws NotCompliantMBeanException
  364      {
  365         try
  366         {
  367            if (info == null)
  368               throw new NotCompliantMBeanException("MBeanInfo cannot be null, for: " + name);
  369   
  370            if (info.getClassName() == null)
  371               throw new NotCompliantMBeanException("Classname returned from MBeanInfo cannot be null, for: " + name);
  372         }
  373         catch (NotCompliantMBeanException ncex)
  374         {
  375            throw ncex;
  376         }
  377         catch (Throwable t)
  378         {
  379            NotCompliantMBeanException ncex = new NotCompliantMBeanException("Cannot verify MBeanInfo, for: " + name);
  380            ncex.initCause(t);
  381            throw ncex;
  382         }
  383      }
  384   
  385      /**
  386        * send a MBeanServerNotification.REGISTRATION_NOTIFICATION notification
  387        * to regName
  388        *
  389        * @param regName
  390        */
  391       protected void sendRegistrationNotification (ObjectName regName)
  392       {
  393           long sequence = registrationNotificationSequence.increment ();
  394           delegate.sendNotification (
  395                   new MBeanServerNotification (
  396                           MBeanServerNotification.REGISTRATION_NOTIFICATION,
  397                           delegate, sequence, regName));
  398       }
  399   
  400       /**
  401        * subclasses can override to provide their own pre-registration pre- and post- logic for
  402        * <tt>preRegister</tt> and must call preRegister on the MBeanRegistration instance
  403        *
  404        * @param registrationInterface
  405        * @param regName
  406        * @return object name
  407        * @throws Exception
  408        */
  409       protected ObjectName handlePreRegistration (MBeanRegistration registrationInterface, ObjectName regName)
  410               throws Exception
  411       {
  412           ObjectName mbean = registrationInterface.preRegister (server, regName);
  413           if (regName == null)
  414           {
  415               return mbean;
  416           }
  417           else
  418           {
  419               return regName;
  420           }
  421       }
  422   
  423   
  424       /**
  425        * subclasses can override to provide any custom preDeregister logic
  426        * and must call preDregister on the MBeanRegistration instance
  427        *
  428        * @param registrationInterface
  429        * @throws Exception
  430        */
  431       protected void handlePreDeregister (MBeanRegistration registrationInterface)
  432               throws Exception
  433       {
  434           registrationInterface.preDeregister ();
  435       }
  436   
  437       /**
  438        * Subclasses can override if they wish to control the classloader
  439        * registration to loader repository.
  440        *
  441        * @param cl classloader
  442        */
  443       protected void registerClassLoader(ClassLoader cl)
  444       {
  445          if( (cl instanceof RealClassLoader) == false )
  446          {
  447            // Only register non-UCLs as UCLs already have a repository
  448            loaderRepository.addClassLoader(cl);
  449          }
  450       }
  451   
  452   
  453      public void unregisterMBean(ObjectName name)
  454         throws InstanceNotFoundException, MBeanRegistrationException
  455      {
  456         name = qualifyName(name);
  457         if (name.getDomain().equals(JMI_DOMAIN))
  458            throw new RuntimeOperationsException(new IllegalArgumentException(
  459               "Not allowed to unregister: " + name.toString()));
  460   
  461         MBeanEntry entry = get(name);
  462         Object resource = entry.getResourceInstance();
  463   
  464         try
  465         {
  466             // allow subclasses to perform their own pre- and post- pre-deregister logic
  467             handlePreDeregister (entry.getInvoker());
  468   
  469         }
  470         catch (Exception e)
  471         {
  472            // don't double wrap MBeanRegistrationException
  473            if (e instanceof MBeanRegistrationException)
  474               throw (MBeanRegistrationException)e;
  475   
  476            throw new MBeanRegistrationException(e, "preDeregister");
  477         }
  478   
  479         // Remove any classloader
  480         if (resource instanceof ClassLoader)
  481            loaderRepository.removeClassLoader((ClassLoader)resource);
  482   
  483         // It is no longer registered
  484         remove(name);
  485   
  486         sendUnRegistrationNotification (name);
  487   
  488         entry.getInvoker().postDeregister();
  489      }
  490   
  491     /**
  492      * send MBeanServerNotification.UNREGISTRATION_NOTIFICATION notification to
  493      * name
  494      *
  495      * @param name
  496      */
  497     protected void sendUnRegistrationNotification (ObjectName name)
  498     {
  499         long sequence = unregistrationNotificationSequence.increment ();
  500   
  501         delegate.sendNotification (
  502                 new MBeanServerNotification (
  503                         MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
  504                         delegate,
  505                         sequence,
  506                         name
  507                 )
  508         );
  509     }
  510   
  511      public MBeanEntry get(ObjectName name)
  512         throws InstanceNotFoundException
  513      {
  514         if (name == null)
  515            throw new RuntimeOperationsException(new IllegalArgumentException("null object name"));
  516   
  517         // Determine the domain and retrieve its entries
  518         String domain = name.getDomain();
  519   
  520         if (domain.length() == 0)
  521            domain = defaultDomain;
  522   
  523         String props = name.getCanonicalKeyPropertyListString();
  524         Map mbeanMap = getMBeanMap(domain, false);
  525   
  526         // Retrieve the mbean entry
  527         Object o = null;
  528         if (null == mbeanMap || null == (o = mbeanMap.get(props)))
  529            throw new InstanceNotFoundException(name + " is not registered.");
  530   
  531         // We are done
  532         return (MBeanEntry) o;
  533      }
  534   
  535      public String getDefaultDomain()
  536      {
  537         return defaultDomain;
  538      }
  539   
  540      public String[] getDomains()
  541      {
  542         ArrayList domains = new ArrayList(domainMap.size());
  543         for (Iterator iterator = domainMap.entrySet().iterator(); iterator.hasNext();)
  544         {
  545            Map.Entry entry = (Map.Entry) iterator.next();
  546            String domainName = (String) entry.getKey();
  547            Map mbeans = (Map) entry.getValue();
  548            if (mbeans != null && mbeans.isEmpty() == false)
  549               domains.add(domainName);
  550         }
  551         return (String[]) domains.toArray(new String[domains.size()]);
  552      }
  553   
  554      public ObjectInstance getObjectInstance(ObjectName name)
  555         throws InstanceNotFoundException
  556      {
  557         if (!contains(name))
  558            throw new InstanceNotFoundException(name + " not registered.");
  559   
  560         return new ServerObjectInstance(qualifyName(name),
  561            get(name).getResourceClassName(), delegate.getMBeanServerId());
  562      }
  563   
  564      public Object getValue(ObjectName name, String key)
  565         throws InstanceNotFoundException
  566      {
  567         return get(name).getValue(key);
  568      }
  569   
  570      public boolean contains(ObjectName name)
  571      {
  572         // null safety check
  573         if (name == null)
  574            return false;
  575   
  576         // Determine the domain and retrieve its entries
  577         String domain = name.getDomain();
  578   
  579         if (domain.length() == 0)
  580            domain = defaultDomain;
  581   
  582         String props = name.getCanonicalKeyPropertyListString();
  583         Map mbeanMap = getMBeanMap(domain, false);
  584   
  585         // Return the result
  586         return (null != mbeanMap && mbeanMap.containsKey(props));
  587      }
  588   
  589      public  int getSize()
  590      {
  591         int retval = 0;
  592          for (Iterator iterator = domainMap.values().iterator(); iterator.hasNext();)
  593          {
  594             retval += ((Map)iterator.next()).size();
  595          }
  596      	 return retval;
  597      }
  598   
  599      public List findEntries(ObjectName pattern)
  600      {
  601         ArrayList retval = new ArrayList();
  602   
  603         // There are a couple of shortcuts we can employ to make this a
  604         // bit faster - they're commented.
  605   
  606         // First, if pattern == null or pattern.getCanonicalName() == "*:*" we want the
  607         // set of all MBeans.
  608         if (pattern == null || pattern.getCanonicalName().equals("*:*"))
  609         {
  610             for (Iterator domainIter = domainMap.values().iterator(); domainIter.hasNext();)
  611                retval.addAll(((Map)domainIter.next()).values());
  612         }
  613         // Next, if !pattern.isPattern() then we are doing a simple get (maybe defaultDomain).
  614         else if (!pattern.isPattern())
  615         {
  616            // simple get
  617            try
  618            {
  619               retval.add(get(pattern));
  620            }
  621            catch (InstanceNotFoundException e)
  622            {
  623               // we don't care
  624            }
  625         }
  626         // Now we have to do a brute force, oh well.
  627         else
  628         {
  629            String patternDomain = pattern.getDomain();
  630            if (patternDomain.length() == 0)
  631               patternDomain = defaultDomain;
  632            PropertyPattern propertyPattern = new PropertyPattern(pattern);
  633   
  634            // Here we go, step through every domain and see if our pattern matches before optionally checking
  635            // each ObjectName's properties for a match.
  636            for (Iterator domainIter = domainMap.entrySet().iterator(); domainIter.hasNext();)
  637            {
  638               Map.Entry mapEntry = (Map.Entry) domainIter.next();
  639               Map value = (Map) mapEntry.getValue();
  640               if (value != null && value.isEmpty() == false)
  641               {
  642                  if (ObjectNamePatternHelper.patternMatch((String) mapEntry.getKey(), patternDomain))
  643                  {
  644                     for (Iterator mbeanIter = value.values().iterator(); mbeanIter.hasNext();)
  645                     {
  646                        MBeanEntry entry = (MBeanEntry) mbeanIter.next();
  647                        if (propertyPattern.patternMatch(entry.getObjectName()))
  648                           retval.add(entry);
  649                     }
  650                  }
  651               }
  652            }
  653         }
  654   
  655         return retval;
  656      }
  657   
  658   
  659      /**
  660       * Cleans up the registry before the MBean server is released.
  661       */
  662      public void releaseRegistry()
  663         // This is based on patch by Rod Burgett (Bug report: 763378)
  664         // Modified. Server is calling the registry.
  665      {
  666          server = null;
  667          delegate = null;
  668   
  669          //  clear each value element from the domainMap
  670          for (Iterator iterator = domainMap.keySet().iterator(); iterator.hasNext();)
  671          {
  672             Map nextMap = (Map) domainMap.get(iterator.next());
  673   
  674             if ( nextMap.size() > 0 )
  675             {
  676                nextMap.clear();
  677             }
  678          }
  679   
  680          domainMap.clear();
  681          domainMap = null;
  682      }
  683   
  684   
  685      // Protected -----------------------------------------------------
  686   
  687      protected ObjectName invokePreRegister(MBeanInvoker invoker, ObjectName regName, String magicToken)
  688         throws MBeanRegistrationException, NotCompliantMBeanException
  689      {
  690   
  691         // if we were given a non-null object name for registration, qualify it
  692         // and expand default domain
  693         if (regName != null)
  694            regName = qualifyName(regName);
  695   
  696         // store the name returned by preRegister() here
  697         ObjectName mbeanName = null;
  698   
  699         try
  700         {
  701            // invoke preregister on the invoker, it will delegate to the resource
  702            // if needed
  703            mbeanName = invoker.preRegister(server, regName);
  704         }
  705         // if during pre registration, the mbean turns out to be not compliant
  706         catch (NotCompliantMBeanException ncex)
  707         {
  708            throw ncex;
  709   
  710         }
  711         // catch all exceptions cause by preRegister, these will abort registration
  712         catch (Exception e)
  713         {
  714            if (e instanceof MBeanRegistrationException)
  715            {
  716               throw (MBeanRegistrationException)e;
  717            }
  718   
  719            throw new MBeanRegistrationException(e,
  720                  "preRegister() failed: " +
  721                  "[ObjectName='" + regName +
  722                  "', Class=" + invoker.getResource().getClass().getName() +
  723                  " (" + invoker.getResource() + ")]"
  724            );
  725         }
  726         catch (Throwable t)
  727         {
  728            log.warn("preRegister() failed for " + regName + ": ", t);
  729   
  730            if (t instanceof Error)
  731               throw new RuntimeErrorException((Error)t);
  732            else
  733               throw new RuntimeException(t.toString());
  734         }
  735   
  736   
  737         // if registered with null name, use the default name returned by
  738         // the preregister implementation
  739         if (regName == null)
  740            regName = mbeanName;
  741   
  742         return validateAndQualifyName(regName, magicToken);
  743      }
  744   
  745      /**
  746       * Adds an MBean entry<p>
  747       *
  748       * WARNING: The object name should be fully qualified.
  749       *
  750       * @param entry the MBean entry to add
  751       * @exception InstanceAlreadyExistsException when the MBean's object name
  752       *            is already registered
  753       */
  754      protected synchronized void add(MBeanEntry entry)
  755         throws InstanceAlreadyExistsException
  756      {
  757         // Determine the MBean's name and properties
  758         ObjectName name = entry.getObjectName();
  759         String domain = name.getDomain();
  760         String props = name.getCanonicalKeyPropertyListString();
  761   
  762         // Create a properties -> entry map if we don't have one
  763         Map mbeanMap = getMBeanMap(domain, true);
  764   
  765         // Make sure we aren't already registered
  766         if (mbeanMap.get(props) != null)
  767            throw new InstanceAlreadyExistsException(name + " already registered.");
  768   
  769         // Ok, we are registered
  770         mbeanMap.put(props, entry);
  771      }
  772   
  773      /**
  774       * Removes an MBean entry
  775       *
  776       * WARNING: The object name should be fully qualified.
  777       *
  778       * @param name the object name of the entry to remove
  779       * @exception InstanceNotFoundException when the object name is not
  780       *            registered
  781       */
  782      protected synchronized void remove(ObjectName name)
  783         throws InstanceNotFoundException
  784      {
  785         // Determine the MBean's name and properties
  786         String domain = name.getDomain();
  787         String props = name.getCanonicalKeyPropertyListString();
  788         Map mbeanMap = getMBeanMap(domain, false);
  789   
  790         // Remove the entry, raise an exception when it didn't exist
  791         if (null == mbeanMap || null == mbeanMap.remove(props))
  792            throw new InstanceNotFoundException(name + " not registered.");
  793      }
  794   
  795      /**
  796       * Validates and qualifies an MBean<p>
  797       *
  798       * Validates the name is not a pattern.<p>
  799       *
  800       * Adds the default domain if no domain is specified.<p>
  801       *
  802       * Checks the name is not in the reserved domain JMImplementation when
  803       * the magicToken is not {@link org.jboss.mx.server.ServerConstants#JMI_DOMAIN JMI_DOMAIN}
  804       *
  805       * @param name the name to validate
  806       * @param magicToken used to get access to the reserved domain
  807       * @return the original name or the name prepended with the default domain
  808       *         if no domain is specified.
  809       * @exception RuntimeOperationsException containing an
  810       *            IllegalArgumentException for a problem with the name
  811       */
  812      protected ObjectName validateAndQualifyName(ObjectName name,
  813                                                  String magicToken)
  814      {
  815         // Check for qualification
  816         ObjectName result = qualifyName(name);
  817   
  818         // Make sure the name is not a pattern
  819         if (result.isPattern())
  820            throw new RuntimeOperationsException(
  821                  new IllegalArgumentException("Object name is a pattern:" + name));
  822   
  823         // Check for reserved domain
  824         if (magicToken != JMI_DOMAIN &&
  825             result.getDomain().equals(JMI_DOMAIN))
  826            throw new RuntimeOperationsException(new IllegalArgumentException(
  827                        "Domain " + JMI_DOMAIN + " is reserved"));
  828   
  829         // I can't think of anymore tests, we're done
  830         return result;
  831      }
  832   
  833      /**
  834       * Qualify an object name with the default domain<p>
  835       *
  836       * Adds the default domain if no domain is specified.
  837       *
  838       * @param name the name to qualify
  839       * @return the original name or the name prepended with the default domain
  840       *         if no domain is specified.
  841       * @exception RuntimeOperationsException containing an
  842       *            IllegalArgumentException when there is a problem
  843       */
  844      protected ObjectName qualifyName(ObjectName name)
  845      {
  846         if (name == null)
  847            throw new RuntimeOperationsException(
  848                  new IllegalArgumentException("Null object name"));
  849         try
  850         {
  851            if (name.getDomain().length() == 0)
  852               return new ObjectName(defaultDomain + ":" +
  853                                     name.getCanonicalKeyPropertyListString());
  854            else
  855               return name;
  856         }
  857         catch (MalformedObjectNameException e)
  858         {
  859            throw new RuntimeOperationsException(
  860                  new IllegalArgumentException(e.toString()));
  861         }
  862      }
  863   
  864      /**
  865       * Adds the given MBean Info object to the persistence queue if it explicity denotes
  866       * (via metadata) that it should be stored.
  867       * @todo -- add notification of registration of MBeanInfoDb.
  868       *   It is possible that some MBeans whose MBean Info should be stored are
  869       *   registered before the MBean Info Storage delegate is available.  These
  870       *   MBeans are remembered by the registry and should be added to the storage delegate
  871       *   as soon as it is available.  In the current mechanism, they are added only if another
  872       *   MBean requesting MBean info persistence is registered after the delegate is registered.
  873       *   Someone more familiar with the server could make this more robust by adding
  874       *   a notification mechanism such that the queue is flushed as soon as the
  875       *   delegate is available.  - Matt Munz
  876       * @todo does this code need to be here? can't a notification listener be
  877       *       registered with the MBeanServerDelegate that stores a backlog
  878       *       until the service becomes available?
  879       * @todo the mbInfoStores is a memory leak if the service is never registered
  880       * @todo mbInfoStores is not synchronized correctly
  881       *       Thread1 adds
  882       *       Thread1 clones and invokes
  883       *       Thread2 adds
  884       *       Thread1 clears
  885       *       Thread2's add is lost
  886       * @todo Don't use Vector, performs too fine grained synchronization,
  887       *       probably not important in this case.
  888       */
  889      protected void persistIfRequired(MBeanInfo info, ObjectName name)
  890        throws
  891          MalformedObjectNameException,
  892          InstanceNotFoundException,
  893          MBeanException,
  894          ReflectionException
  895      {
  896        if(!(info instanceof ModelMBeanInfo))
  897        {
  898            return;
  899        }
  900        ModelMBeanInfo mmbInfo = (ModelMBeanInfo) info;
  901        Descriptor descriptor;
  902        try
  903        {
  904           descriptor = mmbInfo.getMBeanDescriptor();
  905        }
  906        catch(MBeanException cause)
  907        {
  908          log.error("Error trying to get descriptors.", cause);
  909          return;
  910        }
  911        if (descriptor == null)
  912           return;
  913        String persistInfo = (String) descriptor.getFieldValue(ModelMBeanConstants.PERSIST_INFO);
  914        if (persistInfo == null)
  915           return; // use default -- no persistence
  916        log.debug("persistInfo: " + persistInfo);
  917        Boolean shouldPersist = new Boolean(persistInfo);
  918        if(!shouldPersist.booleanValue())
  919        {
  920           return;
  921        }
  922        mbInfosToStore().add(name);
  923        // see if MBeanDb is available
  924        if(contains(mbeanInfoService))
  925        {
  926          // flush queue to the MBeanDb
  927          log.debug("flushing queue");
  928          server.invoke(
  929            mbeanInfoService,
  930            "add",
  931            new Object[] { mbInfosToStore().clone() },
  932            new String[] { mbInfosToStore().getClass().getName() });
  933          log.debug("clearing queue");
  934          mbInfosToStore().clear();
  935        }
  936        else
  937        {
  938          log.debug("service is not registered.  items remain in queue");
  939        }
  940      }
  941   
  942      /**
  943       * ObjectName objects bound to MBean Info objects that are waiting to be stored in the
  944       * persistence store.
  945       */
  946      protected Vector mbInfosToStore()
  947      {
  948         if(fMbInfosToStore == null)
  949         {
  950            fMbInfosToStore = new Vector(10);
  951         }
  952         return fMbInfosToStore;
  953      }
  954   
  955      /**
  956       * The <code>getMBeanMap</code> method provides synchronized access
  957       * to the mbean map for a domain.  This is actually a solution to a
  958       * bug that resulted in wiping out the jboss domain mbeanMap for no
  959       * apparent reason.
  960       *
  961       * @param domain a <code>String</code> value
  962       * @param createIfMissing a <code>boolean</code> value
  963       * @return a <code>Map</code> value
  964       */
  965      private Map getMBeanMap(String domain, boolean createIfMissing)
  966      {
  967         Map mbeanMap = (Map) domainMap.get(domain);
  968         if (mbeanMap == null && createIfMissing)
  969         {
  970           mbeanMap = new ConcurrentReaderHashMap();
  971           domainMap.put(domain, mbeanMap);
  972         }
  973         return mbeanMap;
  974      }
  975   } 

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