Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » system » [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.system;
   23   
   24   import java.io.IOException;
   25   import java.io.StringWriter;
   26   import java.io.Writer;
   27   import java.util.ArrayList;
   28   import java.util.Collection;
   29   import java.util.HashMap;
   30   import java.util.Iterator;
   31   import java.util.List;
   32   
   33   import javax.management.Attribute;
   34   import javax.management.InstanceNotFoundException;
   35   import javax.management.MBeanAttributeInfo;
   36   import javax.management.MBeanInfo;
   37   import javax.management.MBeanServer;
   38   import javax.management.ObjectName;
   39   import javax.xml.parsers.DocumentBuilder;
   40   import javax.xml.parsers.DocumentBuilderFactory;
   41   import javax.xml.transform.Transformer;
   42   import javax.xml.transform.TransformerException;
   43   import javax.xml.transform.TransformerFactory;
   44   import javax.xml.transform.dom.DOMSource;
   45   import javax.xml.transform.stream.StreamResult;
   46   
   47   import org.jboss.deployment.DeploymentException;
   48   import org.jboss.logging.Logger;
   49   import org.jboss.mx.util.JMXExceptionDecoder;
   50   import org.jboss.system.metadata.ServiceAttributeMetaData;
   51   import org.jboss.system.metadata.ServiceMetaData;
   52   import org.jboss.system.metadata.ServiceMetaDataParser;
   53   import org.jboss.system.metadata.ServiceValueContext;
   54   import org.jboss.util.xml.DOMWriter;
   55   import org.w3c.dom.Document;
   56   import org.w3c.dom.Element;
   57   import org.w3c.dom.Node;
   58   import org.w3c.dom.NodeList;
   59   
   60   /**
   61    * Service configuration helper.
   62    * 
   63    * @author <a href="mailto:marc@jboss.org">Marc Fleury</a>
   64    * @author <a href="mailto:hiram@jboss.org">Hiram Chirino</a>
   65    * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
   66    * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
   67    * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
   68    * @author <a href="adrian@jboss.com">Adrian Brock</a>
   69    * @version <tt>$Revision: 72444 $</tt>
   70    */
   71   public class ServiceConfigurator
   72   {
   73      /** The MBean server which this service is registered in. */
   74      private final MBeanServer server;
   75      
   76      /** The parent service controller */
   77      private final ServiceController serviceController;
   78      
   79      /** The ServiceCreator */
   80      private final ServiceCreator serviceCreator;
   81      
   82      /** The ServiceBinding plugin policy */
   83      private ServiceBinding serviceBinding;
   84   
   85      /** Instance logger. */
   86      private static final Logger log = Logger.getLogger(ServiceConfigurator.class);
   87   
   88      /**
   89       * Configure an MBean
   90       * 
   91       * @param server the server
   92       * @param controller the service controller
   93       * @param objectName the object name
   94       * @param classLoaderName the classloader object name
   95       * @param attrs the attributes
   96       * @throws Exception for any error
   97       */
   98      public static void configure(MBeanServer server, ServiceController controller, ObjectName objectName, ObjectName classLoaderName, Collection<ServiceAttributeMetaData> attrs) throws Exception
   99      {
  100         server = checkMBeanServer(server, controller);
  101         ClassLoader cl = server.getClassLoader(classLoaderName);
  102         configure(server, controller, objectName, cl, attrs);
  103      }
  104      
  105      /**
  106       * Configure an MBean
  107       * 
  108       * @param server the server
  109       * @param controller the service controller
  110       * @param objectName the object name
  111       * @param cl the classloader
  112       * @param attrs the attributes
  113       * @throws Exception for any error
  114       */
  115      public static void configure(MBeanServer server, ServiceController controller, ObjectName objectName, ClassLoader cl, Collection<ServiceAttributeMetaData> attrs) throws Exception
  116      {
  117         ServiceValueContext valueContext = new ServiceValueContext(server, controller, cl);
  118         server = checkMBeanServer(server, controller);
  119         
  120         HashMap<String, MBeanAttributeInfo> attributeMap = getAttributeMap(server, objectName);
  121   
  122         for (ServiceAttributeMetaData attribute : attrs)
  123         {
  124            String attributeName = attribute.getName();
  125            if (attributeName == null || attributeName.length() == 0)
  126               throw new DeploymentException("No or empty attribute name for " + objectName);
  127            MBeanAttributeInfo attributeInfo = attributeMap.get(attributeName);
  128            if (attributeInfo == null)
  129            {
  130               throw new DeploymentException("No Attribute found with name: " + attributeName + " for " + objectName
  131                     +", attributes: "+attributeMap.keySet());
  132            }
  133   
  134            valueContext.setAttributeInfo(attributeInfo);
  135            Object value = null;
  136            ClassLoader previous = SecurityActions.setContextClassLoader(cl);
  137            try
  138            {
  139               value = attribute.getValue(valueContext);
  140            }
  141            finally
  142            {
  143               SecurityActions.resetContextClassLoader(previous);
  144            }
  145            try
  146            {
  147               log.debug(attributeName + " set to " + value + " in " + objectName);
  148               server.setAttribute(objectName, new Attribute(attributeName, value));
  149            }
  150            catch (Throwable t)
  151            {
  152               throw new DeploymentException("Exception setting attribute " + attributeName + " on mbean " + objectName, JMXExceptionDecoder.decode(t));
  153            }
  154         }
  155      }
  156   
  157      /**
  158       * Check the server/controller parameters
  159       * 
  160       * @param server the server
  161       * @param controller the controller
  162       * @return the server
  163       */
  164      private static MBeanServer checkMBeanServer(MBeanServer server, ServiceController controller)
  165      {
  166         if (server != null)
  167            return server;
  168         
  169         if (controller != null)
  170            return controller.getMBeanServer();
  171         
  172         throw new IllegalArgumentException("Either the server or controller must be passed");
  173      }
  174      
  175      /**
  176       * Apply any service binding overrides
  177       *
  178       * @review why isn't the MBeanServer part of this api?
  179       * @param server the server
  180       * @param objectName the object name
  181       * @param serviceBinding the service binding
  182       * @throws Exception for any error
  183       */
  184      public static void applyServiceConfig(MBeanServer server, ObjectName objectName, ServiceBinding serviceBinding) throws Exception
  185      {
  186         try
  187         {
  188            serviceBinding.applyServiceConfig(objectName);
  189         }
  190         catch (Throwable e)
  191         {
  192            // serviceBinding is most probably a dynamic mbean proxy
  193            Throwable t = JMXExceptionDecoder.decode(e);            
  194            log.warn("Failed to apply service binding override for " + objectName, t);         
  195         }
  196      }
  197   
  198      /**
  199       * Get an attribute map for the MBean
  200       * 
  201       * @param server the server
  202       * @param objectName the object name
  203       * @return a map of attribute name to attribute info
  204       * @throws Exception for any error
  205       */
  206      private static HashMap<String, MBeanAttributeInfo> getAttributeMap(MBeanServer server, ObjectName objectName) throws Exception
  207      {
  208         MBeanInfo info;
  209         try
  210         {
  211            info = server.getMBeanInfo(objectName);
  212         }
  213         catch (InstanceNotFoundException e)
  214         {
  215            // The MBean is no longer available
  216            throw new DeploymentException("Trying to configure nonexistent mbean: " + objectName);
  217         }
  218         catch (Exception e)
  219         {
  220            throw new DeploymentException("Could not get mbeanInfo", JMXExceptionDecoder.decode(e));
  221         }
  222         if (info == null)
  223            throw new DeploymentException("MBeanInfo is null for mbean: " + objectName);
  224         MBeanAttributeInfo[] attributes = info.getAttributes();
  225         HashMap<String, MBeanAttributeInfo> attributeMap = new HashMap<String, MBeanAttributeInfo>();
  226         for (int i = 0; i < attributes.length; i++)
  227         {
  228            MBeanAttributeInfo attr = attributes[i];
  229            attributeMap.put(attr.getName(), attr);
  230         }
  231         
  232         return attributeMap;
  233      }
  234      
  235      /**
  236       * Constructor
  237       * 
  238       * @deprecated the service controller no longer uses the service configurator and vice-versa
  239       * @param server the mbean server
  240       * @param serviceController the servie controller
  241       * @param serviceCreator the service creator
  242       */
  243      public ServiceConfigurator(MBeanServer server, ServiceController serviceController, ServiceCreator serviceCreator)
  244      {
  245         if (server == null)
  246            throw new IllegalArgumentException("Null server");
  247         if (serviceCreator == null)
  248            throw new IllegalArgumentException("Null serverCreator");
  249         
  250         this.server = server;
  251         this.serviceController = serviceController;
  252         this.serviceCreator = serviceCreator;
  253         if (serviceController != null)
  254            this.serviceBinding = serviceController.getServiceBinding();
  255      }
  256      
  257      /**
  258       * Dynamically plug-in a ServiceBinding policy
  259       * to possibly override the configuration of a service.
  260       * 
  261       * @param serviceBinding policy
  262       */   
  263      public void setServiceBinding(ServiceBinding serviceBinding)
  264      {
  265         this.serviceBinding = serviceBinding;
  266      }
  267      
  268      /**
  269       * The <code>install</code> method iterates through the mbean tags in the
  270       * supplied xml configuration and creates and configures the mbeans shown.
  271       * The mbean configuration can be nested.
  272       * 
  273       * @deprecated the service controller no longer uses the service configurator and vice-versa
  274       * @param config the xml <code>Element</code> containing the configuration of
  275       * the mbeans to create and configure.
  276       * @param loaderName the classloader's ObjectName
  277       * @return a <code>List</code> of ObjectNames of created mbeans.
  278       * @throws DeploymentException if an error occurs
  279       */
  280      public List<ObjectName> install(Element config, ObjectName loaderName) throws DeploymentException
  281      {
  282         // Parse the xml
  283         ServiceMetaDataParser parser = new ServiceMetaDataParser(config);
  284         List<ServiceMetaData> metaDatas = parser.parse();
  285   
  286         // Track the registered object names
  287         List<ObjectName> result = new ArrayList<ObjectName>(metaDatas.size());
  288   
  289         // Go through each mbean in the passed xml
  290         for (ServiceMetaData metaData : metaDatas)
  291         {
  292            ObjectName objectName = metaData.getObjectName();
  293            Collection<ServiceAttributeMetaData> attrs = metaData.getAttributes();
  294            // Install and configure the mbean
  295            try
  296            {
  297               ServiceCreator.install(server, objectName, metaData, null);
  298               result.add(objectName);
  299               configure(server, null, objectName, loaderName, attrs);
  300               if (serviceBinding != null)
  301                  applyServiceConfig(server, objectName, serviceBinding);
  302            }
  303            catch (Throwable t)
  304            {
  305               // Something went wrong
  306               for (ObjectName name : result)
  307               {
  308                  try
  309                  {
  310                     serviceCreator.remove(name);
  311                  }
  312                  catch (Exception e)
  313                  {
  314                     log.error("Error removing mbean after failed deployment: " + name, e);
  315                  }
  316               }
  317               DeploymentException.rethrowAsDeploymentException("Error during install", t);
  318            }
  319         }
  320         return result;
  321      }
  322   
  323      /**
  324       * Builds a string that consists of the configuration elements of the
  325       * currently running MBeans registered in the server.
  326       * 
  327       * @todo replace with more sophisticated mbean persistence mechanism.
  328       * @param server the MBeanServer
  329       * @param serviceController the service controller
  330       * @param objectNames the object names to retrieve
  331       * @return the xml string
  332       * @throws Exception Failed to construct configuration.
  333       */
  334      public static String getConfiguration(MBeanServer server, ServiceController serviceController, ObjectName[] objectNames) throws Exception
  335      {
  336         Writer out = new StringWriter();
  337   
  338         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  339         DocumentBuilder builder = factory.newDocumentBuilder();
  340         Document doc = builder.newDocument();
  341   
  342         Element serverElement = doc.createElement("server");
  343   
  344         // Store attributes as XML
  345         for (int j = 0; j < objectNames.length; j++)
  346         {
  347            Element mbeanElement = internalGetConfiguration(doc, server, serviceController, objectNames[j]);
  348            serverElement.appendChild(mbeanElement);
  349         }
  350   
  351         doc.appendChild(serverElement);
  352   
  353         // Write configuration
  354         new DOMWriter(out).setPrettyprint(true).print(doc);
  355   
  356         out.close();
  357   
  358         // Return configuration
  359         return out.toString();
  360      }
  361   
  362      private static Element internalGetConfiguration(Document doc, MBeanServer server, ServiceController serviceController, ObjectName name) throws Exception
  363      {
  364         Element mbeanElement = doc.createElement("mbean");
  365         mbeanElement.setAttribute("name", name.toString());
  366   
  367         MBeanInfo info = server.getMBeanInfo(name);
  368         mbeanElement.setAttribute("code", info.getClassName());
  369         MBeanAttributeInfo[] attributes = info.getAttributes();
  370         boolean trace = log.isTraceEnabled();
  371         for (int i = 0; i < attributes.length; i++)
  372         {
  373            if (trace)
  374               log.trace("considering attribute: " + attributes[i]);
  375            if (attributes[i].isReadable() && attributes[i].isWritable())
  376            {
  377               Element attributeElement = null;
  378               if (attributes[i].getType().equals("javax.management.ObjectName"))
  379               {
  380                  attributeElement = doc.createElement("depends");
  381                  attributeElement.setAttribute("optional-attribute-name", attributes[i].getName());
  382               }
  383               else
  384               {
  385                  attributeElement = doc.createElement("attribute");
  386                  attributeElement.setAttribute("name", attributes[i].getName());
  387               }
  388               Object value = server.getAttribute(name, attributes[i].getName());
  389   
  390               if (value != null)
  391               {
  392                  if (value instanceof Element)
  393                  {
  394                     attributeElement.appendChild(doc.importNode((Element) value, true));
  395                  }
  396                  else
  397                  {
  398                     attributeElement.appendChild(doc.createTextNode(value.toString()));
  399                  }
  400               }
  401               mbeanElement.appendChild(attributeElement);
  402            }
  403         }
  404   
  405         ServiceContext sc = serviceController.getServiceContext(name);
  406         for (Iterator i = sc.iDependOn.iterator(); i.hasNext();)
  407         {
  408            ServiceContext needs = (ServiceContext) i.next();
  409            Element dependsElement = doc.createElement("depends");
  410            dependsElement.appendChild(doc.createTextNode(needs.objectName.toString()));
  411            mbeanElement.appendChild(dependsElement);
  412         }
  413   
  414         return mbeanElement;
  415      }
  416   
  417      /**
  418       * Builds a string that consists of the configuration elements of the
  419       * currently running MBeans registered in the server.
  420       * 
  421       * TODO replace with more sophisticated mbean persistence mechanism.
  422       * @param objectNames the object names
  423       * @return the xml string
  424       * @throws Exception Failed to construct configuration.
  425       */
  426      public String getConfiguration(ObjectName[] objectNames) throws Exception
  427      {
  428         return getConfiguration(server, serviceController, objectNames);
  429      }
  430   
  431      /**
  432       * A utility method that transforms the contents of the argument element into
  433       * a StringBuffer representation that can be reparsed.
  434       * 
  435       * [FIXME] This is not a general DOMUtils method because of its funny contract. It does not 
  436       * support multiple child elements neither can it deal with text content.
  437       * 
  438       * @param element - the parent dom element whose contents are to be extracted as an xml document string. 
  439       * @return the xml document string.
  440       * @throws IOException for an error during IO
  441       * @throws TransformerException for an erro during transformation
  442       */
  443      public static StringBuffer getElementContent(Element element) throws IOException, TransformerException
  444      {
  445         NodeList children = element.getChildNodes();
  446         Element content = null;
  447         for (int n = 0; n < children.getLength(); n++)
  448         {
  449            Node node = children.item(n);
  450            if (node.getNodeType() == Node.ELEMENT_NODE)
  451            {
  452               content = (Element)node;
  453               break;
  454            }
  455         }
  456         if (content == null)
  457            return null;
  458   
  459         // Get a parsable representation of this elements content
  460         DOMSource source = new DOMSource(content);
  461         TransformerFactory tFactory = TransformerFactory.newInstance();
  462         Transformer transformer = tFactory.newTransformer();
  463         StringWriter sw = new StringWriter();
  464         StreamResult result = new StreamResult(sw);
  465         transformer.transform(source, result);
  466         sw.close();
  467         return sw.getBuffer();
  468      }
  469   }

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