[jboss-cvs] JBossAS SVN: r90066 - trunk/cluster/src/main/org/jboss/ha/framework/server.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Jun 10 16:42:29 EDT 2009


Author: bstansberry at jboss.com
Date: 2009-06-10 16:42:28 -0400 (Wed, 10 Jun 2009)
New Revision: 90066

Modified:
   trunk/cluster/src/main/org/jboss/ha/framework/server/JChannelFactory.java
Log:
[JBAS-7009] Don't subclass JGroups' JChannelFactory

Modified: trunk/cluster/src/main/org/jboss/ha/framework/server/JChannelFactory.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/framework/server/JChannelFactory.java	2009-06-10 20:00:45 UTC (rev 90065)
+++ trunk/cluster/src/main/org/jboss/ha/framework/server/JChannelFactory.java	2009-06-10 20:42:28 UTC (rev 90066)
@@ -21,10 +21,16 @@
  */
 package org.jboss.ha.framework.server;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.net.InetAddress;
+import java.net.URL;
 import java.rmi.dgc.VMID;
 import java.rmi.server.UID;
 import java.security.AccessController;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -35,6 +41,8 @@
 import javax.management.MBeanRegistration;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 
 import org.jboss.bootstrap.spi.util.ServerConfigUtil;
 import org.jboss.logging.Logger;
@@ -49,6 +57,7 @@
 import org.jboss.util.loading.ContextClassLoaderSwitcher;
 import org.jgroups.Channel;
 import org.jgroups.ChannelException;
+import org.jgroups.ChannelFactory;
 import org.jgroups.ChannelListenerAdapter;
 import org.jgroups.Event;
 import org.jgroups.Global;
@@ -57,6 +66,7 @@
 import org.jgroups.conf.ProtocolData;
 import org.jgroups.conf.ProtocolStackConfigurator;
 import org.jgroups.conf.ProtocolParameter;
+import org.jgroups.conf.XmlConfigurator;
 import org.jgroups.jmx.JmxConfigurator;
 import org.jgroups.protocols.TP;
 import org.jgroups.stack.IpAddress;
@@ -68,6 +78,11 @@
 import org.jgroups.util.ThreadFactory;
 import org.jgroups.util.ThreadManager;
 import org.jgroups.util.Util;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * Extension to the JGroups JChannelFactory that supports a number of 
@@ -94,8 +109,8 @@
  */
 @ManagementObject(componentType=@ManagementComponent(type="MCBean", subtype="JChannelFactory"),
       properties=ManagementProperties.CLASS_AND_EXPLICIT)
-public class JChannelFactory extends org.jgroups.JChannelFactory
-      implements JChannelFactoryMBean, MBeanRegistration
+public class JChannelFactory //extends org.jgroups.JChannelFactory
+      implements ChannelFactory, JChannelFactoryMBean, MBeanRegistration
 {
    private static final Logger log = Logger.getLogger(JChannelFactory.class);
    
@@ -109,6 +124,11 @@
    private static final int DESTROYED = ServiceMBean.DESTROYED;
    private static final int FAILED = ServiceMBean.FAILED;
    
+   private static final String PROTOCOL_STACKS="protocol_stacks";
+   private static final String STACK="stack";
+   private static final String NAME="name";
+   private static final String CONFIG="config";
+   
    private InetAddress nodeAddress;
    private String nodeName;
    private int namingServicePort = -1;
@@ -121,6 +141,106 @@
    private final ContextClassLoaderSwitcher classLoaderSwitcher;
    private final Set<String> registeredChannels = new HashSet<String>();
 
+   /**
+    * Map<String,ProtocolStackConfigurator>. Hashmap which maps stack names to JGroups
+    * configurations. Keys are stack names, values are plain JGroups stack
+    * configs. This is (re-)populated whenever a setMultiplexerConfig() method
+    * is called
+    */
+   private final Map<String,ProtocolStackConfigurator> stacks = Collections.synchronizedMap(new HashMap<String, ProtocolStackConfigurator>());
+
+   /**
+    * The MBeanServer to expose JMX management data with (no management data
+    * will be available if null)
+    */
+   private MBeanServer server = null;
+
+   /** To expose the channels and protocols */
+   private String domain = "jgroups";
+
+   /** Whether or not to expose channels via JMX */
+   private boolean expose_channels=true;
+
+   /** Whether to expose the factory only, or all protocols as well */
+   private boolean expose_protocols=true;
+
+   public static Map<String, ProtocolStackConfigurator> parse(InputStream input) throws Exception 
+   {
+      DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
+      factory.setValidating(false); //for now
+      DocumentBuilder builder=factory.newDocumentBuilder();
+      Document document=builder.parse(input);
+
+      // The root element of the document should be the "config" element,
+      // but the parser(Element) method checks this so a check is not
+      // needed here.
+      Element configElement = document.getDocumentElement();
+      return parse(configElement);
+   }
+   
+   public static Map<String, ProtocolStackConfigurator> parse(Element root) throws Exception 
+   {
+      /**
+        * CAUTION: crappy code ahead ! I (bela) am not an XML expert, so the code below is pretty amateurish...
+        * But it seems to work, and it is executed only on startup, so no perf loss on the critical path.
+        * If somebody wants to improve this, please be my guest.
+        */
+      String root_name = root.getNodeName();
+      if (!PROTOCOL_STACKS.equals(root_name.trim().toLowerCase()))
+      {
+         String error = "XML protocol stack configuration does not start with a '<config>' element; "
+               + "maybe the XML configuration needs to be converted to the new format ?\n"
+               + "use 'java org.jgroups.conf.XmlConfigurator <old XML file> -new_format' to do so";
+         throw new IOException("invalid XML configuration: " + error);
+      }
+
+      Map<String, ProtocolStackConfigurator> result = new HashMap<String, ProtocolStackConfigurator>();
+
+      NodeList tmp_stacks = root.getChildNodes();
+      for (int i = 0; i < tmp_stacks.getLength(); i++)
+      {
+         Node node = tmp_stacks.item(i);
+         if (node.getNodeType() != Node.ELEMENT_NODE)
+            continue;
+
+         Element stack = (Element) node;
+         String tmp = stack.getNodeName();
+         if (!STACK.equals(tmp.trim().toLowerCase()))
+         {
+            throw new IOException("invalid configuration: didn't find a \"" + STACK + "\" element under \""
+                  + PROTOCOL_STACKS + "\"");
+         }
+
+         NamedNodeMap attrs = stack.getAttributes();
+         Node name = attrs.getNamedItem(NAME);
+         // Node descr=attrs.getNamedItem(DESCR);
+         String st_name = name.getNodeValue();
+         // String stack_descr=descr.getNodeValue();
+         // System.out.print("Parsing \"" + st_name + "\" (" + stack_descr + ")");
+         NodeList configs = stack.getChildNodes();
+         for (int j = 0; j < configs.getLength(); j++)
+         {
+            Node tmp_config = configs.item(j);
+            if (tmp_config.getNodeType() != Node.ELEMENT_NODE)
+               continue;
+            Element cfg = (Element) tmp_config;
+            tmp = cfg.getNodeName();
+            if (!CONFIG.equals(tmp))
+               throw new IOException("invalid configuration: didn't find a \"" + CONFIG + "\" element under \"" + STACK
+                     + "\"");
+
+            XmlConfigurator conf = XmlConfigurator.getInstance(cfg);
+            // fixes http://jira.jboss.com/jira/browse/JGRP-290
+            ConfiguratorFactory.substituteVariables(conf); // replace vars with system props
+
+            result.put(st_name, conf);
+         }
+      }
+
+      return result;
+   }
+
+   @SuppressWarnings("unchecked")
    public JChannelFactory()
    {
       this.classLoaderSwitcher = (ContextClassLoaderSwitcher) AccessController.doPrivileged(ContextClassLoaderSwitcher.INSTANTIATOR);
@@ -129,19 +249,17 @@
    /**
     * Always throws <code>ChannelException</code>; this method is not supported.
     */   
-   @Override
    public Channel createChannel() throws ChannelException
    {
       throw new ChannelException("No-arg createChannel() is not supported");
    }
 
-   @Override
    public Channel createChannel(Object properties) throws ChannelException
    {
       checkStarted();
       
       @SuppressWarnings("deprecation")      
-      Channel channel = super.createChannel(properties);
+      Channel channel = new JChannel(properties);
       
       if (manageNewThreadClassLoader || manageReleasedThreadClassLoader)
       {
@@ -168,7 +286,6 @@
     * 
     * @throws Exception
     */
-   @Override
    public Channel createChannel(String stack_name) throws Exception
    {
       checkStarted();
@@ -238,7 +355,6 @@
     *                               <code>false</code>.
     * @throws ChannelException
     */
-   @Override
    public Channel createMultiplexerChannel(String stack_name, String id) throws Exception
    {
       checkStarted();
@@ -313,20 +429,76 @@
     *                               <code>false</code>.
     * @throws ChannelException
     */
-   @Override
    public Channel createMultiplexerChannel(String stack_name, String id, boolean register_for_state_transfer, String substate_id) throws Exception
    {
       return createMultiplexerChannel(stack_name, id);
    }
    
+   public void setMultiplexerConfig(Element properties) throws Exception
+   {
+      setMultiplexerConfig(properties, true);
+   }
+
+   public void setMultiplexerConfig(File properties) throws Exception
+   {
+      setMultiplexerConfig(properties, true);
+      
+   }
+
+   public void setMultiplexerConfig(Object properties) throws Exception
+   {
+      setMultiplexerConfig(properties, true);
+   }
+
+   public void setMultiplexerConfig(String properties) throws Exception
+   {
+      setMultiplexerConfig(properties, true);
+   }
+
+   public void setMultiplexerConfig(URL properties) throws Exception
+   {
+      setMultiplexerConfig(properties, true);
+   }
+
+   // -------------------------------------------------------------  Properties
+
+   public MBeanServer getServer() {
+       return server;
+   }
+
+   public void setServer(MBeanServer server) {
+       this.server=server;
+   }
+
+   public String getDomain() {
+       return domain;
+   }
+   
    @ManagementProperty(use={ViewUse.CONFIGURATION}, description="The domain portion of the JMX ObjectName to use when registering channels and protocols")
-   @Override
    public void setDomain(String domain)
    {
-      super.setDomain(domain);
+      this.domain = domain;
       domainSet = true;
    }
 
+   public boolean isExposeChannels() {
+       return expose_channels;
+   }
+
+   public void setExposeChannels(boolean expose_channels) {
+       this.expose_channels=expose_channels;
+   }
+
+   public boolean isExposeProtocols() {
+       return expose_protocols;
+   }
+
+   public void setExposeProtocols(boolean expose_protocols) {
+       this.expose_protocols=expose_protocols;
+       if (expose_protocols)
+          this.expose_channels=true;
+   }
+
    /**
     * Get any logical name assigned to this server; if not null this value
     * will be the value of the 
@@ -531,8 +703,139 @@
    {
       this.addMissingSingletonName = addMissingSingletonName;
    }
+   
+   // -------------------------------------------------------------  Public
 
-   @Override
+   public void setMultiplexerConfig(Element properties, boolean replace) throws Exception
+   {
+      Map<String, ProtocolStackConfigurator> map = parse(properties);
+      
+   }
+
+   public void setMultiplexerConfig(File properties, boolean replace) throws Exception
+   {
+      InputStream input=ConfiguratorFactory.getConfigStream(properties);      
+      addConfigs(input, properties.toString(), replace);
+   }
+
+   public void setMultiplexerConfig(Object properties, boolean replace) throws Exception
+   {
+      InputStream input=ConfiguratorFactory.getConfigStream(properties);
+      addConfigs(input, properties.toString(), replace);   
+   }
+
+   public void setMultiplexerConfig(String properties, boolean replace) throws Exception
+   {
+      InputStream input=ConfiguratorFactory.getConfigStream(properties);      
+      addConfigs(input, properties, replace);
+   }
+
+   public void setMultiplexerConfig(URL url, boolean replace) throws Exception
+   {
+      InputStream input=ConfiguratorFactory.getConfigStream(url);      
+      addConfigs(input, url.toString(), replace);
+   }
+
+   private void addConfigs(InputStream input, String source, boolean replace) throws Exception
+   {
+      if(input == null)
+      {
+         throw new FileNotFoundException(source);
+      }
+      
+      Map<String, ProtocolStackConfigurator> map = null;
+      try {
+          map = parse(input);
+      }
+      catch(Exception ex) {
+          throw new Exception("failed parsing " + source, ex);
+      }
+      finally {
+          Util.close(input);
+      }
+      
+      for (Map.Entry<String, ProtocolStackConfigurator> entry : map.entrySet())
+      {
+         addConfig(entry.getKey(), entry.getValue(), replace);
+      }
+   }
+   
+   // ---------------------------------------------------  JChannelFactoryMBean
+   
+
+
+   private boolean addConfig(String st_name, ProtocolStackConfigurator val, boolean replace)
+   {
+      boolean added = replace;
+      if(replace) {
+         stacks.put(st_name, val);
+         if(log.isTraceEnabled())
+             log.trace("added config '" + st_name + "'");
+     }
+     else {
+         if(!stacks.containsKey(st_name)) {
+             stacks.put(st_name, val);
+             if(log.isTraceEnabled())
+                 log.trace("added config '" + st_name + "'");
+             replace = true;
+         }
+         else {
+             if(log.isTraceEnabled())
+                 log.trace("didn't add config '" + st_name + " because one of the same name already existed");
+         }
+     }
+      return replace;
+      
+   }
+
+   public void clearConfigurations()
+   {
+      this.stacks.clear();
+   }
+
+   public String dumpChannels()
+   {
+      return "";
+   }
+
+   public String dumpConfiguration()
+   {
+      return stacks.keySet().toString();
+   }
+
+   /**
+    * Returns the stack configuration as a string (to be fed into new JChannel()). Throws an exception
+    * if the stack_name is not found. One of the setMultiplexerConfig() methods had to be called beforehand
+    * @return The protocol stack config as a plain string
+    */
+   public String getConfig(String stack_name) throws Exception
+   {
+      ProtocolStackConfigurator cfg = stacks.get(stack_name);
+      if (cfg == null)
+         throw new Exception("stack \"" + stack_name + "\" not found in " + stacks.keySet());
+      return cfg.getProtocolStackString();
+   }
+
+   /**
+    * @return Returns all configurations
+    */
+   public String getMultiplexerConfig()
+   {
+      StringBuilder sb = new StringBuilder();
+      for (Map.Entry<String, ProtocolStackConfigurator> entry : stacks.entrySet())
+      {
+         sb.append(entry.getKey()).append(": ").append(entry.getValue().getProtocolStackString()).append("\n");
+      }
+      return sb.toString();
+   }
+
+   public boolean removeConfig(String stack_name)
+   {
+      return stack_name != null && this.stacks.remove(stack_name) != null;
+   }
+   
+   // -------------------------------------------------------------  Lifecycle
+
    public void create() throws Exception
    {
 
@@ -547,7 +850,7 @@
       
       try
       {
-         super.create();
+         createService();
          state = CREATED;
       }
       catch (Exception e)
@@ -559,7 +862,22 @@
       log.debug("Created JChannelFactory");
    }
 
-   @Override
+   protected void createService() throws Exception
+   {
+      if(expose_channels) 
+      {
+         if(server == null)
+            server=Util.getMBeanServer();
+         if(server == null)
+         {
+            throw new Exception("No MBeanServer found; JChannelFactory needs to be run with an MBeanServer present, " +
+                      "e.g. inside JBoss or JDK 5, or with ExposeChannels set to false");
+         }
+         if(domain == null)
+            domain="jgroups";
+      }
+   }
+
    public void start() throws Exception
    {
       if (state == STARTING || state == STARTED || state == STOPPING)
@@ -579,7 +897,7 @@
 
       try
       {
-         super.start();
+         startService();
       }
       catch (Exception e)
       {
@@ -593,7 +911,11 @@
       
    }
 
-   @Override
+   protected void startService() throws Exception
+   {
+      // no-op
+   }
+
    public void stop()
    {
       if (state != STARTED)
@@ -607,7 +929,7 @@
 
       try
       {
-         super.stop();
+         stopService();
       }
       catch (Throwable e)
       {
@@ -620,7 +942,11 @@
       log.debug("Stopped JChannelFactory");
    }
 
-   @Override
+   protected void stopService() throws Exception
+   {
+      // no-op
+   }
+
    public void destroy()
    {
       if (state == DESTROYED)
@@ -637,21 +963,9 @@
       
       log.debug("Destroying JChannelFactory");
       
-      // DON'T call super.destroy() as that may deregister the JMX proxy
-      // to this pojo service, leading to ugliness when the proxy is destroyed
       try
-      {
-         
-         Set<String> toUnregister = null;
-         synchronized (registeredChannels)
-         {
-            toUnregister = new HashSet<String>(registeredChannels);
-         }
-         
-         for (String channelId : toUnregister)
-         {
-            unregister(channelId);
-         }
+      {         
+         destroyService();
       }
       catch (Throwable t)
       {
@@ -661,6 +975,20 @@
       log.debug("Destroyed JChannelFactory");
    }
 
+   protected void destroyService()
+   {
+      Set<String> toUnregister = null;
+      synchronized (registeredChannels)
+      {
+         toUnregister = new HashSet<String>(registeredChannels);
+      }
+      
+      for (String channelId : toUnregister)
+      {
+         unregister(channelId);
+      }
+   }
+
    // ------------------------------------------------------- MBeanRegistration
 
    public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception




More information about the jboss-cvs-commits mailing list