[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