All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.system.ServiceConfigurator Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.system;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import javax.management.Attribute;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.jboss.logging.Logger;
import org.jboss.mx.util.JMXExceptionDecoder;
import org.jboss.system.metadata.ServiceAttributeMetaData;
import org.jboss.system.metadata.ServiceMetaData;
import org.jboss.system.metadata.ServiceMetaDataParser;
import org.jboss.system.metadata.ServiceValueContext;
import org.jboss.util.xml.DOMWriter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Service configuration helper.
 * 
 * @author Marc Fleury
 * @author Hiram Chirino
 * @author David Jencks
 * @author Jason Dillon
 * @author Dimitris Andreadis
 * @author Adrian Brock
 * @version $Revision: 81485 $
 */
public class ServiceConfigurator
{
   /** The MBean server which this service is registered in. */
   private final MBeanServer server;
   
   /** The parent service controller */
   private final ServiceController serviceController;
   
   /** The ServiceCreator */
   private final ServiceCreator serviceCreator;

   /** Instance logger. */
   private static final Logger log = Logger.getLogger(ServiceConfigurator.class);

   /**
    * Rethrow an error as an exception
    * 
    * @param context the context
    * @param t the original throwable
    * @return never
    * @throws Exception always
    */
   public static Exception rethrow(String context, Throwable t) throws Exception
   {
      if (t instanceof Error)
         throw (Error) t;
      else if (t instanceof Exception)
         throw (Exception) t;
      throw new RuntimeException(context, t);
   }

   /**
    * Configure an MBean
    * 
    * @param server the server
    * @param controller the service controller
    * @param objectName the object name
    * @param classLoaderName the classloader object name
    * @param attrs the attributes
    * @throws Exception for any error
    */
   public static void configure(MBeanServer server, ServiceController controller, ObjectName objectName, ObjectName classLoaderName, Collection attrs) throws Exception
   {
      server = checkMBeanServer(server, controller);
      ClassLoader cl = server.getClassLoader(classLoaderName);
      configure(server, controller, objectName, cl, attrs);
   }
   
   /**
    * Configure an MBean
    * 
    * @param server the server
    * @param controller the service controller
    * @param objectName the object name
    * @param cl the classloader
    * @param attrs the attributes
    * @throws Exception for any error
    */
   public static void configure(MBeanServer server, ServiceController controller, ObjectName objectName, ClassLoader cl, Collection attrs) throws Exception
   {
      ServiceValueContext valueContext = new ServiceValueContext(server, controller, cl);
      server = checkMBeanServer(server, controller);
      
      HashMap attributeMap = getAttributeMap(server, objectName);

      for (ServiceAttributeMetaData attribute : attrs)
      {
         String attributeName = attribute.getName();
         if (attributeName == null || attributeName.length() == 0)
            throw new RuntimeException("No or empty attribute name for " + objectName);
         MBeanAttributeInfo attributeInfo = attributeMap.get(attributeName);
         if (attributeInfo == null)
         {
            throw new RuntimeException("No Attribute found with name: " + attributeName + " for " + objectName
                  +", attributes: "+attributeMap.keySet());
         }

         valueContext.setAttributeInfo(attributeInfo);
         Object value = null;
         ClassLoader previous = SecurityActions.setContextClassLoader(cl);
         try
         {
            value = attribute.getValue(valueContext);
         }
         finally
         {
            SecurityActions.resetContextClassLoader(previous);
         }
         try
         {
            if (log.isDebugEnabled())
            {
               Object outputValue = value;
               if (attributeName.toLowerCase().indexOf("password") != -1)
                  outputValue = "****";
               log.debug(attributeName + " set to " + outputValue + " in " + objectName);
            }
            server.setAttribute(objectName, new Attribute(attributeName, value));
         }
         catch (Throwable t)
         {
            throw new RuntimeException("Exception setting attribute " + attributeName + " on mbean " + objectName, JMXExceptionDecoder.decode(t));
         }
      }
   }

   /**
    * Check the server/controller parameters
    * 
    * @param server the server
    * @param controller the controller
    * @return the server
    */
   private static MBeanServer checkMBeanServer(MBeanServer server, ServiceController controller)
   {
      if (server != null)
         return server;
      
      if (controller != null)
         return controller.getMBeanServer();
      
      throw new IllegalArgumentException("Either the server or controller must be passed");
   }

   /**
    * Get an attribute map for the MBean
    * 
    * @param server the server
    * @param objectName the object name
    * @return a map of attribute name to attribute info
    * @throws Exception for any error
    */
   private static HashMap getAttributeMap(MBeanServer server, ObjectName objectName) throws Exception
   {
      MBeanInfo info;
      try
      {
         info = server.getMBeanInfo(objectName);
      }
      catch (InstanceNotFoundException e)
      {
         // The MBean is no longer available
         throw new RuntimeException("Trying to configure nonexistent mbean: " + objectName);
      }
      catch (Exception e)
      {
         throw new RuntimeException("Could not get mbeanInfo", JMXExceptionDecoder.decode(e));
      }
      if (info == null)
         throw new RuntimeException("MBeanInfo is null for mbean: " + objectName);
      MBeanAttributeInfo[] attributes = info.getAttributes();
      HashMap attributeMap = new HashMap();
      for (int i = 0; i < attributes.length; i++)
      {
         MBeanAttributeInfo attr = attributes[i];
         attributeMap.put(attr.getName(), attr);
      }
      
      return attributeMap;
   }
   
   /**
    * Constructor
    * 
    * @deprecated the service controller no longer uses the service configurator and vice-versa
    * @param server the mbean server
    * @param serviceController the servie controller
    * @param serviceCreator the service creator
    */
   public ServiceConfigurator(MBeanServer server, ServiceController serviceController, ServiceCreator serviceCreator)
   {
      if (server == null)
         throw new IllegalArgumentException("Null server");
      if (serviceCreator == null)
         throw new IllegalArgumentException("Null serverCreator");
      
      this.server = server;
      this.serviceController = serviceController;
      this.serviceCreator = serviceCreator;
   }
   
   /**
    * The install method iterates through the mbean tags in the
    * supplied xml configuration and creates and configures the mbeans shown.
    * The mbean configuration can be nested.
    * 
    * @deprecated the service controller no longer uses the service configurator and vice-versa
    * @param config the xml Element containing the configuration of
    * the mbeans to create and configure.
    * @param loaderName the classloader's ObjectName
    * @return a List of ObjectNames of created mbeans.
    * @throws Exception if an error occurs
    */
   public List install(Element config, ObjectName loaderName) throws Exception
   {
      // Parse the xml
      ServiceMetaDataParser parser = new ServiceMetaDataParser(config);
      List metaDatas = parser.parse();

      // Track the registered object names
      List result = new ArrayList(metaDatas.size());

      // Go through each mbean in the passed xml
      for (ServiceMetaData metaData : metaDatas)
      {
         ObjectName objectName = metaData.getObjectName();
         Collection attrs = metaData.getAttributes();
         // Install and configure the mbean
         try
         {
            ServiceCreator.install(server, objectName, metaData, null);
            result.add(objectName);
            configure(server, null, objectName, loaderName, attrs);
         }
         catch (Throwable t)
         {
            // Something went wrong
            for (ObjectName name : result)
            {
               try
               {
                  serviceCreator.remove(name);
               }
               catch (Exception e)
               {
                  log.error("Error removing mbean after failed deployment: " + name, e);
               }
            }
            throw rethrow("Error during install", t);
         }
      }
      return result;
   }

   /**
    * Builds a string that consists of the configuration elements of the
    * currently running MBeans registered in the server.
    * 
    * @todo replace with more sophisticated mbean persistence mechanism.
    * @param server the MBeanServer
    * @param serviceController the service controller
    * @param objectNames the object names to retrieve
    * @return the xml string
    * @throws Exception Failed to construct configuration.
    */
   public static String getConfiguration(MBeanServer server, ServiceController serviceController, ObjectName[] objectNames) throws Exception
   {
      Writer out = new StringWriter();

      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document doc = builder.newDocument();

      Element serverElement = doc.createElement("server");

      // Store attributes as XML
      for (int j = 0; j < objectNames.length; j++)
      {
         Element mbeanElement = internalGetConfiguration(doc, server, serviceController, objectNames[j]);
         serverElement.appendChild(mbeanElement);
      }

      doc.appendChild(serverElement);

      // Write configuration
      new DOMWriter(out).setPrettyprint(true).print(doc);

      out.close();

      // Return configuration
      return out.toString();
   }

   private static Element internalGetConfiguration(Document doc, MBeanServer server, ServiceController serviceController, ObjectName name) throws Exception
   {
      Element mbeanElement = doc.createElement("mbean");
      mbeanElement.setAttribute("name", name.toString());

      MBeanInfo info = server.getMBeanInfo(name);
      mbeanElement.setAttribute("code", info.getClassName());
      MBeanAttributeInfo[] attributes = info.getAttributes();
      boolean trace = log.isTraceEnabled();
      for (int i = 0; i < attributes.length; i++)
      {
         if (trace)
            log.trace("considering attribute: " + attributes[i]);
         if (attributes[i].isReadable() && attributes[i].isWritable())
         {
            Element attributeElement = null;
            if (attributes[i].getType().equals("javax.management.ObjectName"))
            {
               attributeElement = doc.createElement("depends");
               attributeElement.setAttribute("optional-attribute-name", attributes[i].getName());
            }
            else
            {
               attributeElement = doc.createElement("attribute");
               attributeElement.setAttribute("name", attributes[i].getName());
            }
            Object value = server.getAttribute(name, attributes[i].getName());

            if (value != null)
            {
               if (value instanceof Element)
               {
                  attributeElement.appendChild(doc.importNode((Element) value, true));
               }
               else
               {
                  attributeElement.appendChild(doc.createTextNode(value.toString()));
               }
            }
            mbeanElement.appendChild(attributeElement);
         }
      }

      ServiceContext sc = serviceController.getServiceContext(name);
      for (ServiceContext needs : sc.iDependOn)
      {
         Element dependsElement = doc.createElement("depends");
         dependsElement.appendChild(doc.createTextNode(needs.objectName.toString()));
         mbeanElement.appendChild(dependsElement);
      }

      return mbeanElement;
   }

   /**
    * Builds a string that consists of the configuration elements of the
    * currently running MBeans registered in the server.
    * 
    * TODO replace with more sophisticated mbean persistence mechanism.
    * @param objectNames the object names
    * @return the xml string
    * @throws Exception Failed to construct configuration.
    */
   public String getConfiguration(ObjectName[] objectNames) throws Exception
   {
      return getConfiguration(server, serviceController, objectNames);
   }

   /**
    * A utility method that transforms the contents of the argument element into
    * a StringBuffer representation that can be reparsed.
    * 
    * [FIXME] This is not a general DOMUtils method because of its funny contract. It does not 
    * support multiple child elements neither can it deal with text content.
    * 
    * @param element - the parent dom element whose contents are to be extracted as an xml document string. 
    * @return the xml document string.
    * @throws IOException for an error during IO
    * @throws TransformerException for an erro during transformation
    */
   public static StringBuffer getElementContent(Element element) throws IOException, TransformerException
   {
      NodeList children = element.getChildNodes();
      Element content = null;
      for (int n = 0; n < children.getLength(); n++)
      {
         Node node = children.item(n);
         if (node.getNodeType() == Node.ELEMENT_NODE)
         {
            content = (Element)node;
            break;
         }
      }
      if (content == null)
         return null;

      // Get a parsable representation of this elements content
      DOMSource source = new DOMSource(content);
      TransformerFactory tFactory = TransformerFactory.newInstance();
      Transformer transformer = tFactory.newTransformer();
      StringWriter sw = new StringWriter();
      StreamResult result = new StreamResult(sw);
      transformer.transform(source, result);
      sw.close();
      return sw.getBuffer();
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy