Author: pferraro
Date: 2008-09-03 15:37:13 -0400 (Wed, 03 Sep 2008)
New Revision: 1774
Added:
trunk/mod_cluster/.classpath
trunk/mod_cluster/.project
trunk/mod_cluster/pom.xml
trunk/mod_cluster/src/
trunk/mod_cluster/src/main/
trunk/mod_cluster/src/main/java/
trunk/mod_cluster/src/main/java/org/
trunk/mod_cluster/src/main/java/org/jboss/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/BasicClusterListener.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/Constants.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/DefaultJBossWebEventHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/JBossWebEventHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/LocalStrings.properties
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterService.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterServiceMBean.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/Utils.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseEventType.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseListener.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertisedServer.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/BalancerConfiguration.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/MCMPHandlerConfiguration.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/ModClusterConfig.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/NodeConfiguration.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/SSLConfiguration.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerImpl.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/HASingletonAwareResetRequestSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ModClusterServiceDRMEntry.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/BooleanGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponseFilter.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/InetAddressGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/IntegerGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/MCMPServerDiscoveryEvent.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceRpcHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceStateGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/StringGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ThrowableGroupRpcResponse.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/LoadBalanceFactorProvider.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProvider.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProviderMBean.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/StaticLoadBalanceFactorProvider.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricMBean.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSourceRegistration.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ActiveSessionsLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AverageSystemLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/BusyConnectorsLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolUsageLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/DeterministicLoadState.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/HeapMemoryUsageLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeRatioLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanQueryLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/OperatingSystemLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ReceiveTrafficLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestCountLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestProcessorLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SendTrafficLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SessionLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SingleLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SystemMemoryUsageLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadCountLoadMetric.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadPoolLoadMetricSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mbeans-descriptors.xml
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AbstractMCMPHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AddressPort.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequest.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequestType.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServer.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServerState.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPUtils.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/ResetRequestSource.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/DefaultMCMPHandler.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSEKeyManager.java
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSESocketFactory.java
trunk/mod_cluster/src/main/resources/
trunk/mod_cluster/src/main/resources/mod-cluster-jboss-beans.xml
trunk/mod_cluster/src/test/
trunk/mod_cluster/src/test/java/
trunk/mod_cluster/src/test/java/org/
trunk/mod_cluster/src/test/java/org/jboss/
trunk/mod_cluster/src/test/java/org/jboss/modcluster/
trunk/mod_cluster/src/test/java/org/jboss/modcluster/ha/
trunk/mod_cluster/src/test/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/DynamicLoadBalanceFactorProviderTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/StaticLoadBalanceFactorProviderTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ActiveSessionsLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/AverageSystemLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/BusyConnectorsLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ConnectionPoolUsageLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/HeapMemoryUsageLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ReceiveTrafficLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/RequestCountLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SendTrafficLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SystemMemoryUsageLoadMetricTestCase.java
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ThreadCountLoadMetricTestCase.java
Removed:
trunk/mod_cluster/test/native/
Log:
Moved here from
http://svn.jboss.org/jbossas/trunk/tomcat
Added: trunk/mod_cluster/.classpath
===================================================================
--- trunk/mod_cluster/.classpath (rev 0)
+++ trunk/mod_cluster/.classpath 2008-09-03 19:37:13 UTC (rev 1774)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var"
path="M2_REPO/org/jboss/cluster/jboss-ha-server-api/1.1.0.GA/jboss-ha-server-api-1.1.0.GA.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/jboss/web/jbossweb/2.1.1.CR6/jbossweb-2.1.1.CR6.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/org/jboss/logging/jboss-logging-spi/2.0.5.GA/jboss-logging-spi-2.0.5.GA.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/org/easymock/easymock/2.4/easymock-2.4.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/org/jboss/microcontainer/jboss-kernel/2.0.0.Beta17/jboss-kernel-2.0.0.Beta17.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/junit/junit/4.4/junit-4.4.jar"/>
+ <classpathentry kind="output" path="target"/>
+</classpath>
Added: trunk/mod_cluster/.project
===================================================================
--- trunk/mod_cluster/.project (rev 0)
+++ trunk/mod_cluster/.project 2008-09-03 19:37:13 UTC (rev 1774)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>mod_cluster</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
Added: trunk/mod_cluster/pom.xml
===================================================================
--- trunk/mod_cluster/pom.xml (rev 0)
+++ trunk/mod_cluster/pom.xml 2008-09-03 19:37:13 UTC (rev 1774)
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.jboss</groupId>
+ <artifactId>jboss-parent</artifactId>
+ <version>3</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.jboss.native</groupId>
+ <artifactId>mod_cluster</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name></name>
+ <description></description>
+ <url></url>
+
+ <scm>
+
<
connection>scm:svn:https://svn.jboss.org/repos/jbossnative/trunk/mod_c...
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <printSummary>true</printSummary>
+ <disableXmlReport>false</disableXmlReport>
+ <includes>
+ <include>**/*TestCase.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+
<
tagBase>https://svn.jboss.org/repos/jbossnative/tags/mod_cluster</t...
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.cluster</groupId>
+ <artifactId>jboss-ha-server-api</artifactId>
+ <version>1.1.0.GA</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss.web</groupId>
+ <artifactId>jbossweb</artifactId>
+ <version>2.1.1.CR6</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.microcontainer</groupId>
+ <artifactId>jboss-kernel</artifactId>
+ <version>2.0.0.Beta14</version>
+ </dependency>
+
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ <version>1.0</version>
+ </dependency>
+
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>2.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/BasicClusterListener.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/BasicClusterListener.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/BasicClusterListener.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,236 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt 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.modcluster;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerEvent;
+import org.apache.catalina.ContainerListener;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+import org.apache.catalina.util.StringManager;
+import org.jboss.logging.Logger;
+
+/**
+ * This listener communicates with a front end mod_cluster enabled proxy to
+ * automatically maintain the node configuration according to what is
+ * deployed.
+ */
+public class BasicClusterListener implements LifecycleListener, ContainerListener
+{
+ protected static Logger log = Logger.getLogger(BasicClusterListener.class);
+
+ /**
+ * The string manager for this package.
+ */
+ protected StringManager sm = StringManager.getManager(Constants.Package);
+
+ // -------------------------------------------------------------- Constants
+
+ // ----------------------------------------------------------------- Fields
+
+ /**
+ * Initialization flag.
+ */
+ protected boolean init = false;
+
+ protected JBossWebEventHandler eventHandler;
+
+ // ----------------------------------------------------------- Constructors
+
+ public BasicClusterListener(JBossWebEventHandler eventHandler)
+ {
+ this.eventHandler = eventHandler;
+ }
+
+ protected BasicClusterListener()
+ {
+ }
+
+ // ------------------------------------------------------------- Properties
+
+ // ---------------------------------------------- LifecycleListener Methods
+
+ /**
+ * Acknowledge the occurrence of the specified event.
+ * Note: Will never be called when the listener is associated to a Server,
+ * since it is not a Container.
+ *
+ * @param event ContainerEvent that has occurred
+ */
+ public void containerEvent(ContainerEvent event)
+ {
+ Container container = event.getContainer();
+ Object child = event.getData();
+ String type = event.getType();
+
+ if (type.equals(Container.ADD_CHILD_EVENT))
+ {
+ if (container instanceof Host)
+ {
+ // Deploying a webapp
+ ((Lifecycle) child).addLifecycleListener(this);
+ this.eventHandler.addContext((Context) child);
+ }
+ else if (container instanceof Engine)
+ {
+ // Deploying a host
+ container.addContainerListener(this);
+ }
+ }
+ else if (type.equals(Container.REMOVE_CHILD_EVENT))
+ {
+ if (container instanceof Host)
+ {
+ // Undeploying a webapp
+ ((Lifecycle) child).removeLifecycleListener(this);
+ this.eventHandler.removeContext((Context) child);
+ }
+ else if (container instanceof Engine)
+ {
+ // Undeploying a host
+ container.removeContainerListener(this);
+ }
+ }
+
+ }
+
+ /**
+ * Primary entry point for startup and shutdown events.
+ *
+ * @param event The event that has occurred
+ */
+ public void lifecycleEvent(LifecycleEvent event)
+ {
+ Object source = event.getLifecycle();
+
+ if (Lifecycle.START_EVENT.equals(event.getType()))
+ {
+ if (source instanceof Context)
+ {
+ // Start a webapp
+ this.eventHandler.startContext((Context) source);
+ }
+ }
+ else if (Lifecycle.AFTER_START_EVENT.equals(event.getType()))
+ {
+ if (source instanceof Server)
+ {
+ this.eventHandler.init();
+
+ this.startServer((Server) source);
+
+ this.init = true;
+ }
+ }
+ else if (Lifecycle.STOP_EVENT.equals(event.getType()))
+ {
+ if (source instanceof Context)
+ {
+ // Stop a webapp
+ this.eventHandler.stopContext((Context) source);
+ }
+ else if (source instanceof Server)
+ {
+ this.stopServer((Server) source);
+
+ this.eventHandler.shutdown();
+
+ this.init = false;
+ }
+ }
+ else if (Lifecycle.PERIODIC_EVENT.equals(event.getType()))
+ {
+ if (this.init && source instanceof Engine)
+ {
+ this.eventHandler.status((Engine) source);
+ }
+ }
+ }
+
+ /**
+ * Send commands to the front end server associated with the startup of the
+ * node.
+ */
+ protected void startServer(Server server)
+ {
+ // Register ourself as a listener for child services
+ Service[] services = server.findServices();
+ for (Service service : services)
+ {
+ service.getContainer().addContainerListener(this);
+
+ Engine engine = (Engine) service.getContainer();
+ ((Lifecycle) engine).addLifecycleListener(this);
+
+ Container[] children = engine.findChildren();
+ for (Container element : children)
+ {
+ element.addContainerListener(this);
+ Container[] children2 = element.findChildren();
+ for (Container element2 : children2)
+ {
+ ((Lifecycle) element2).addLifecycleListener(this);
+ }
+ }
+ }
+
+ this.eventHandler.startServer(server);
+ }
+
+ /**
+ * Send commands to the front end server associated with the shutdown of the
+ * node.
+ */
+ protected void stopServer(Server server)
+ {
+ // Register ourself as a listener to child components
+ Service[] services = server.findServices();
+ for (Service service : services)
+ {
+ service.getContainer().removeContainerListener(this);
+ ((Lifecycle) service.getContainer()).removeLifecycleListener(this);
+ Container[] children = service.getContainer().findChildren();
+ for (Container element : children)
+ {
+ element.removeContainerListener(this);
+ Container[] children2 = element.findChildren();
+ for (Container element2 : children2)
+ {
+ ((Lifecycle) element2).removeLifecycleListener(this);
+ }
+ }
+ }
+
+ this.eventHandler.stopServer(server);
+ }
+
+ protected void setEventHandler(JBossWebEventHandler handler)
+ {
+ this.eventHandler = handler;
+ }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/Constants.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/Constants.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/Constants.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,27 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt 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.modcluster;
+
+public class Constants
+{
+ public static final String Package = Constants.class.getPackage().getName();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/DefaultJBossWebEventHandler.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/DefaultJBossWebEventHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/DefaultJBossWebEventHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,302 @@
+/*
+ * 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.modcluster;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.util.StringManager;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.advertise.AdvertiseListener;
+import org.jboss.modcluster.config.BalancerConfiguration;
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+import org.jboss.modcluster.config.NodeConfiguration;
+import org.jboss.modcluster.load.LoadBalanceFactorProvider;
+import org.jboss.modcluster.mcmp.AddressPort;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPUtils;
+
+/**
+ * Default implementation of {@link JBossWebEventHandler}.
+ *
+ * @author Brian Stansberry
+ */
+public class DefaultJBossWebEventHandler implements JBossWebEventHandler
+{
+ protected static Logger log = Logger.getLogger(DefaultJBossWebEventHandler.class);
+
+ // ----------------------------------------------------------------- Fields
+
+ /**
+ * The string manager for this package.
+ */
+ private final StringManager sm = StringManager.getManager(Constants.Package);
+ private final NodeConfiguration nodeConfiguration;
+ private final BalancerConfiguration balancerConfiguration;
+ private final MCMPHandler mcmpHandler;
+ private final LoadBalanceFactorProvider loadBalanceFactorProvider;
+
+ private boolean init;
+
+ private AdvertiseListener advertiseListener;
+
+ // ----------------------------------------------------------- Constructors
+
+ public DefaultJBossWebEventHandler(NodeConfiguration nodeConfiguration,
BalancerConfiguration balancerConfiguration,
+ MCMPHandler mcmpHandler, LoadBalanceFactorProvider loadBalanceFactorProvider)
+ {
+ this.nodeConfiguration = nodeConfiguration;
+ this.balancerConfiguration = balancerConfiguration;
+ this.mcmpHandler = mcmpHandler;
+ this.loadBalanceFactorProvider = loadBalanceFactorProvider;
+ }
+
+ // ---------------------------------------------------- JBossWebEventHandler
+
+ public synchronized void init()
+ {
+ MCMPHandlerConfiguration handlerConfig = this.mcmpHandler.getConfiguration();
+ List<AddressPort> initialProxies =
MCMPUtils.parseProxies(handlerConfig.getProxyList());
+ this.mcmpHandler.init(initialProxies);
+
+ Boolean advertise = handlerConfig.getAdvertise();
+
+ if (Boolean.TRUE.equals(advertise) || (advertise == null &&
initialProxies.size() == 0))
+ {
+ this.advertiseListener = new AdvertiseListener(this.mcmpHandler);
+ }
+
+ this.init = true;
+ }
+
+ public synchronized void shutdown()
+ {
+ this.stopListener();
+ this.mcmpHandler.shutdown();
+ this.init = false;
+ }
+
+ /**
+ * Send commands to the front end server associated with the startup of the
+ * node.
+ */
+ public void startServer(Server server)
+ {
+ this.checkInit();
+
+ Service[] services = server.findServices();
+ for (Service service : services)
+ {
+ Engine engine = (Engine) service.getContainer();
+
+ this.config(engine);
+ Container[] children = engine.findChildren();
+ for (Container element : children)
+ {
+ Container[] children2 = element.findChildren();
+ for (Container element2 : children2)
+ {
+ this.addContext((Context) element2);
+ }
+ }
+ }
+ }
+
+ /**
+ * Send commands to the front end server associated with the shutdown of the
+ * node.
+ */
+ public void stopServer(Server server)
+ {
+ this.checkInit();
+
+ Service[] services = server.findServices();
+ for (Service service : services)
+ {
+ this.removeAll((Engine) service.getContainer());
+ Container[] children = service.getContainer().findChildren();
+ for (Container element : children)
+ {
+ Container[] children2 = element.findChildren();
+ for (Container element2 : children2)
+ {
+ this.removeContext((Context) element2);
+ }
+ }
+ }
+ }
+
+ public void config(Engine engine)
+ {
+ log.debug(this.sm.getString("modcluster.engine.config",
engine.getName()));
+
+ // If needed, create automagical JVM route (address + port + engineName)
+ try
+ {
+ Utils.establishJvmRouteAndConnectorAddress(engine, this.mcmpHandler);
+ }
+ catch (Exception e)
+ {
+ this.mcmpHandler.markProxiesInError();
+ log.info(this.sm.getString("modcluster.error.addressJvmRoute"), e);
+ return;
+ }
+
+ MCMPRequest request = MCMPUtils.createConfigRequest(engine,
this.getNodeConfiguration(), this.getBalancerConfiguration());
+
+ // Send CONFIG request
+ this.mcmpHandler.sendRequest(request);
+ }
+
+ public void addContext(Context context)
+ {
+ this.checkInit();
+
+ log.debug(this.sm.getString("modcluster.context.enable",
context.getPath(), context.getParent().getName(), ((StandardContext)
context).getState()));
+
+ // Send ENABLE-APP if state is started
+ if (context.isStarted())
+ {
+ MCMPRequest request = MCMPUtils.createEnableAppRequest(context);
+ this.mcmpHandler.sendRequest(request);
+ }
+ }
+
+ public void startContext(Context context)
+ {
+ this.checkInit();
+
+ log.debug(this.sm.getString("modcluster.context.start",
context.getPath(), context.getParent().getName()));
+
+ // Send ENABLE-APP
+ MCMPRequest request = MCMPUtils.createEnableAppRequest(context);
+ this.mcmpHandler.sendRequest(request);
+ }
+
+ public void stopContext(Context context)
+ {
+ this.checkInit();
+
+ log.debug(this.sm.getString("modcluster.context.stop", context.getPath(),
context.getParent().getName()));
+
+ // Send STOP-APP
+ MCMPRequest request = MCMPUtils.createStopAppRequest(context);
+ this.mcmpHandler.sendRequest(request);
+ }
+
+ public void removeContext(Context context)
+ {
+ this.checkInit();
+
+ log.debug(this.sm.getString("modcluster.context.disable",
context.getPath(), context.getParent().getName(), ((StandardContext)
context).getState()));
+
+ // JVMRoute can be null here if nothing was ever initialized
+ if (Utils.getJvmRoute(context) != null)
+ {
+ MCMPRequest request = MCMPUtils.createRemoveAppRequest(context);
+ this.mcmpHandler.sendRequest(request);
+ }
+ }
+
+ public void removeAll(Engine engine)
+ {
+ this.checkInit();
+
+ log.debug(this.sm.getString("modcluster.engine.stop",
engine.getName()));
+
+ // JVMRoute can be null here if nothing was ever initialized
+ if (engine.getJvmRoute() != null)
+ {
+ // Send REMOVE-APP * request
+ MCMPRequest request = MCMPUtils.createRemoveAllRequest(engine);
+ this.mcmpHandler.sendRequest(request);
+ }
+ }
+
+ public void status(Engine engine)
+ {
+ this.checkInit();
+
+ log.debug(this.sm.getString("modcluster.engine.status",
engine.getName()));
+
+ this.mcmpHandler.status();
+
+ // Send STATUS request
+ int lbf = this.getLoadBalanceFactorProvider().getLoadBalanceFactor();
+ MCMPRequest request = MCMPUtils.createStatusRequest(engine, lbf);
+ this.mcmpHandler.sendRequest(request);
+ }
+
+ // ----------------------------------------------------------------- Public
+
+ public BalancerConfiguration getBalancerConfiguration()
+ {
+ return this.balancerConfiguration;
+ }
+
+ public NodeConfiguration getNodeConfiguration()
+ {
+ return this.nodeConfiguration;
+ }
+
+ public LoadBalanceFactorProvider getLoadBalanceFactorProvider()
+ {
+ return this.loadBalanceFactorProvider;
+ }
+
+ // ---------------------------------------------------------------- Private
+
+ private void checkInit()
+ {
+ if (!this.init)
+ {
+ throw new
IllegalStateException(this.sm.getString("modcluster.error.uninitialized"));
+ }
+ }
+
+ /**
+ * Stop the advertise listener.
+ */
+ private void stopListener()
+ {
+ if (this.advertiseListener != null)
+ {
+ try
+ {
+ this.advertiseListener.destroy();
+ }
+ catch (IOException e)
+ {
+ log.error(this.sm.getString("modcluster.error.stopListener"), e);
+ }
+ this.advertiseListener = null;
+ }
+ }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/JBossWebEventHandler.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/JBossWebEventHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/JBossWebEventHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,55 @@
+/*
+ * 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.modcluster;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Server;
+
+/**
+ * Handles events notifications coming from JBoss Web via a cluster listener.
+ *
+ * @author Brian Stansberry
+ */
+public interface JBossWebEventHandler
+{
+ void init();
+ void shutdown();
+
+ void addContext(Context context);
+
+ void startContext(Context context);
+
+ void stopContext(Context context);
+
+ void removeContext(Context context);
+
+ void config(Engine engine);
+
+ void removeAll(Engine engine);
+
+ void status(Engine engine);
+
+ void startServer(Server server);
+
+ void stopServer(Server server);
+}
\ No newline at end of file
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/LocalStrings.properties
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/LocalStrings.properties
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/LocalStrings.properties 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,40 @@
+# Regular messages
+modcluster.context.disable=Undeploy context [{0}] with state [{2}] to Host [{1}]
+modcluster.context.enable=Deploy context [{0}] with state [{2}] to Host [{1}]
+modcluster.context.start=Start context [{0}] in Host [{1}]
+modcluster.context.stop=Stop context [{0}] in Host [{1}]
+modcluster.engine.config=Sending configuration for engine [{0}]
+modcluster.engine.status=Check status for engine [{0}]
+modcluster.engine.stop=Stop all web applications for engine [{0}]
+modcluster.request=Sending command [{0}] wildcard [{1}] to proxy [{2}]
+modcluster.singleton.ignorestop=Ignoring call to stopOldMaster for domain [{0}] as we are
in domain [{1}]
+modcluster.util.address=Detected local address [{0}]
+modcluster.util.jvmRoute=Engine [{0}] will use jvmRoute [{1}]
+
+# Error messages
+modcluster.error.addressJvmRoute=Error connecting to proxy to determine Engine.JVMRoute
or Connector.address
+modcluster.error.discovery.add=Failure notifying master of added proxy [{0}]:[{1}]
+modcluster.error.discovery.remove=Failure notifying master of removed proxy [{0}]:[{1}]
+modcluster.error.drm="Error updating DRM
+modcluster.error.invalidHost=Invalid host specified: {0}
+modcluster.error.io=IO error sending command {0} to proxy {1}
+modcluster.error.jmxRegister=Error during JMX registration
+modcluster.error.jmxUnregister=Error during JMX unregistration
+modcluster.error.noproxy=No proxy list or URL configured, advertise disabled and no
localhost available; connect connect to mod_cluster
+modcluster.error.nonPositiveAttribute=Invalid {0} specified [{1}] - must be a positive
number.
+modcluster.error.nullAttribute=Value for attribute {0} cannot be null
+modcluster.error.other=Error [{2}: {3}] sending command {0} to proxy {1}, configuration
will be reset
+modcluster.error.iae.null=[{0}] is null
+modcluster.error.iae.invalid="Invalid value [{0}] for [{1}]
+modcluster.error.parse=Error parsing response header for command {0}
+modcluster.error.rpc.known=Call to [{0}] received throwable from [{1}]
+modcluster.error.rpc.noresp=No valid response to RPC [{0}]
+modcluster.error.rpc.unknown=Call to [{0}] received throwable from unknown server
+modcluster.error.rpc.unexpected=Unexpected response [{0}] to RPC [{1}]
+modcluster.error.startListener=Error starting advertise listener
+modcluster.error.status.complete=Caught exception advising cluster of status upddate
completion
+modcluster.error.status.unsupported=status() should not be invoked on
ClusteredMCMPHandler
+modcluster.error.stopListener=Error stopping advertise listener
+modcluster.error.stopOldMaster=Call to stopOldMaster failed. New master singleton will
not start.
+modcluster.error.syntax=Unrecoverable syntax error [{2}: {3}] sending command {0} to
proxy {1}
+modcluster.error.uninitialized=Not initialized; call init() first
\ No newline at end of file
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterService.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterService.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterService.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,899 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Server;
+import org.apache.catalina.util.StringManager;
+import org.jboss.beans.metadata.api.annotations.Inject;
+import org.jboss.beans.metadata.api.model.FromContext;
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
+import org.jboss.ha.framework.interfaces.HAPartition;
+import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
+import org.jboss.ha.framework.server.HAServiceEvent;
+import org.jboss.ha.framework.server.HAServiceEventFactory;
+import org.jboss.ha.framework.server.HAServiceImpl;
+import org.jboss.ha.framework.server.HAServiceRpcHandler;
+import org.jboss.ha.framework.server.HASingletonImpl;
+import org.jboss.modcluster.config.BalancerConfiguration;
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+import org.jboss.modcluster.config.ModClusterConfig;
+import org.jboss.modcluster.config.NodeConfiguration;
+import org.jboss.modcluster.ha.ClusteredMCMPHandler;
+import org.jboss.modcluster.ha.ClusteredMCMPHandlerImpl;
+import org.jboss.modcluster.ha.HASingletonAwareResetRequestSource;
+import org.jboss.modcluster.ha.ModClusterServiceDRMEntry;
+import org.jboss.modcluster.load.LoadBalanceFactorProvider;
+import org.jboss.modcluster.mcmp.AddressPort;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPServer;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+import org.jboss.modcluster.mcmp.MCMPUtils;
+import org.jboss.modcluster.ha.rpc.BooleanGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler;
+import org.jboss.modcluster.ha.rpc.GroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
+import org.jboss.modcluster.ha.rpc.ModClusterServiceRpcHandler;
+import org.jboss.modcluster.ha.rpc.ModClusterServiceStateGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.PeerMCMPDiscoveryStatus;
+import org.jboss.modcluster.ha.rpc.ResetRequestGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.ResetRequestSourceRpcHandler;
+import org.jboss.modcluster.ha.rpc.StringGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.ThrowableGroupRpcResponse;
+import org.jboss.modcluster.mcmp.impl.DefaultMCMPHandler;
+
+/**
+ * A ModClusterService.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public class ModClusterService extends HASingletonImpl<HAServiceEvent>
+ implements JBossWebEventHandler, ModClusterServiceMBean,
ModClusterServiceRpcHandler<List<?>, MCMPServerState>
+{
+ private static final Class<?>[] CLUSTER_STATUS_COMPLETE_TYPES = new Class[] {
Map.class };
+ private static final Class<?>[] GET_CLUSTER_COORDINATOR_STATE_TYPES = new
Class[] { Set.class };
+
+ // ----------------------------------------------------------------- Fields
+
+ final MCMPHandler localHandler;
+ final ClusteredMCMPHandler clusteredHandler;
+ final HASingletonAwareResetRequestSource resetRequestSource;
+ final Map<ClusterNode, MCMPServerDiscoveryEvent> proxyChangeDigest =
+ new HashMap<ClusterNode, MCMPServerDiscoveryEvent>();
+
+ /**
+ * The string manager for this package.
+ */
+ final StringManager sm = StringManager.getManager(Constants.Package);
+
+ private final LoadBalanceFactorProvider loadManager;
+ private final RpcHandler rpcHandler;
+ private final JBossWebEventHandler eventHandlerDelegate;
+ private final String domain;
+ private final boolean masterPerDomain;
+
+ volatile int latestLoad;
+ private volatile int statusCount = 0;
+ private volatile int processStatusFrequency = 1;
+ private ModClusterServiceDRMEntry drmEntry;
+
+ /**
+ * Create a new ClusterCoordinator.
+ *
+ * @param partition the partition of which we are a member
+ * @param config our configuration
+ * @param loadFactorProvider source for local load balance statistics
+ */
+ public ModClusterService(HAPartition partition,
+ ModClusterConfig config,
+ LoadBalanceFactorProvider loadFactorProvider)
+ {
+ this(partition, config, loadFactorProvider, null);
+ }
+
+
+ /**
+ * Create a new ClusterCoordinator.
+ *
+ * @param partition the partition of which we are a member
+ * @param config our configuration
+ * @param loadFactorProvider source for local load balance statistics
+ * @param singletonElector chooses the singleton master
+ */
+ public ModClusterService(HAPartition partition,
+ ModClusterConfig config,
+ LoadBalanceFactorProvider loadFactorProvider,
+ HASingletonElectionPolicy electionPolicy)
+ {
+ super(new HAServiceEventFactory());
+
+ assert partition != null :
this.sm.getString("modcluster.error.iae.null", "partition");
+ assert loadFactorProvider != null :
this.sm.getString("modcluster.error.iae.null", "loadFactorProvider");
+ assert config != null :
this.sm.getString("modcluster.error.iae.null", "config is null");
+
+ this.setHAPartition(partition);
+
+ this.resetRequestSource = new HASingletonAwareResetRequestSource(config, config,
this);
+ this.localHandler = new DefaultMCMPHandler(config, this.resetRequestSource);
+// this.localHandler.init();
+ this.clusteredHandler = new ClusteredMCMPHandlerImpl(this.localHandler, this);
+ this.loadManager = loadFactorProvider;
+ this.eventHandlerDelegate = new DefaultJBossWebEventHandler(config, config,
this.clusteredHandler, loadFactorProvider);
+ this.domain = config.getDomain();
+ this.masterPerDomain = config.isMasterPerDomain();
+
+ this.setElectionPolicy(electionPolicy);
+
+ this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), null);
+
+ this.rpcHandler = new RpcHandler();
+ }
+
+ /**
+ * Create a new ClusterCoordinator using the given component parts.
+ * Only intended for use by test suites that may wish to inject
+ * mock components.
+ *
+ * @param partition
+ * @param nodeConfig
+ * @param balancerConfig
+ * @param localHandler
+ * @param resetRequestSource
+ * @param clusteredHandler
+ * @param loadManager
+ * @param singletonElector
+ */
+ protected ModClusterService(HAPartition partition,
+ NodeConfiguration nodeConfig,
+ BalancerConfiguration balancerConfig,
+ MCMPHandlerConfiguration mcmpHandlerConfig,
+ MCMPHandler localHandler,
+ HASingletonAwareResetRequestSource resetRequestSource,
+ ClusteredMCMPHandler clusteredHandler,
+ LoadBalanceFactorProvider loadManager,
+ HASingletonElectionPolicy electionPolicy)
+ {
+ super(new HAServiceEventFactory());
+
+ assert partition != null :
this.sm.getString("modcluster.error.iae.null", "partition");
+ assert localHandler != null :
this.sm.getString("modcluster.error.iae.null", "localHandler");
+ assert loadManager != null :
this.sm.getString("modcluster.error.iae.null", "loadManager");
+ assert resetRequestSource != null :
this.sm.getString("modcluster.error.iae.null", "resetRequestSource");
+ assert nodeConfig != null :
this.sm.getString("modcluster.error.iae.null", "nodeConfig");
+ assert balancerConfig != null :
this.sm.getString("modcluster.error.iae.null", "balancerConfig");
+ assert clusteredHandler != null :
this.sm.getString("modcluster.error.iae.null", "clusteredHandler");
+
+ this.setHAPartition(partition);
+
+ this.localHandler = localHandler;
+ this.resetRequestSource = resetRequestSource;
+ this.clusteredHandler = clusteredHandler;
+ this.loadManager = loadManager;
+ this.eventHandlerDelegate = new DefaultJBossWebEventHandler(nodeConfig,
balancerConfig, clusteredHandler, loadManager);
+ this.domain = nodeConfig.getDomain();
+ this.masterPerDomain = mcmpHandlerConfig.isMasterPerDomain();
+
+ this.setElectionPolicy(electionPolicy);
+
+ this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), null);
+
+ this.rpcHandler = new RpcHandler();
+ }
+
+ // -------------------------------------------------- ModClusterServiceMBean
+
+ public void addProxy(String host, int port)
+ {
+ this.clusteredHandler.addProxy(host, port);
+ }
+
+
+ public void removeProxy(String host, int port)
+ {
+ this.clusteredHandler.removeProxy(host, port);
+ }
+
+
+ public String getProxyConfiguration()
+ {
+ return this.clusteredHandler.getProxyConfiguration();
+ }
+
+
+ public void refresh()
+ {
+ this.clusteredHandler.markProxiesInError();
+ }
+
+
+ public void reset()
+ {
+ this.clusteredHandler.reset();
+ }
+
+
+ // ---------------------------------------------------- JBossWebEventHandler
+
+
+ public void init()
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.init();
+ }
+
+ public void shutdown()
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.shutdown();
+ }
+
+
+ public void startServer(Server server)
+ {
+ // Pass on ref to our server
+ this.resetRequestSource.setJbossWebServer(server);
+
+ // Use the standard logic
+ this.eventHandlerDelegate.startServer(server);
+ }
+
+ public void stopServer(Server server)
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.stopServer(server);
+ }
+
+ public void config(Engine engine)
+ {
+ // If needed, create automagical JVM route (address + port + engineName)
+ try
+ {
+ Utils.establishJvmRouteAndConnectorAddress(engine, this.clusteredHandler);
+ }
+ catch (Exception e) {
+ this.clusteredHandler.markProxiesInError();
+ this.log.info(this.sm.getString("modcluster.error.addressJvmRoute"),
e);
+ return;
+ }
+
+ this.drmEntry.addJvmRoute(engine.getJvmRoute());
+ this.updateLocalDRM(this.drmEntry);
+
+ // Use the standard logic
+ this.eventHandlerDelegate.config(engine);
+ }
+
+ public void removeAll(Engine engine)
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.removeAll(engine);
+
+ this.drmEntry.removeJvmRoute(engine.getJvmRoute());
+ this.updateLocalDRM(this.drmEntry);
+ }
+
+ public void addContext(Context context)
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.addContext(context);
+ }
+
+ public void startContext(Context context)
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.startContext(context);
+ }
+
+ public void stopContext(Context context)
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.stopContext(context);
+ }
+
+ public void removeContext(Context context)
+ {
+ // Use the standard logic
+ this.eventHandlerDelegate.removeContext(context);
+ }
+
+ public void status(Engine engine)
+ {
+ this.latestLoad = this.loadManager.getLoadBalanceFactor();
+
+ if (this.isMasterNode())
+ {
+ this.statusCount = (this.statusCount + 1) % this.processStatusFrequency;
+ if (this.statusCount == 0)
+ {
+ this.updateClusterStatus();
+ }
+ }
+ }
+
+
+ // ------------------------------------------------------------- Properties
+
+ public String getDomain()
+ {
+ return this.domain;
+ }
+
+ public int getProcessStatusFrequency()
+ {
+ return this.processStatusFrequency;
+ }
+
+ public void setProcessStatusFrequency(int processStatusFrequency)
+ {
+ this.processStatusFrequency = processStatusFrequency;
+ }
+
+
+ // ------------------------------------------------------- Public Overrides
+
+ @Override
+ public void startSingleton()
+ {
+ super.startSingleton();
+
+ this.clusteredHandler.setMasterNode(true);
+ this.resetRequestSource.setMasterNode(true);
+
+ // Ensure we do a full status on the next event
+ this.statusCount = this.processStatusFrequency - 1;
+ }
+
+ @Override
+ public void stopSingleton()
+ {
+ super.stopSingleton();
+
+ this.clusteredHandler.setMasterNode(false);
+ this.resetRequestSource.setMasterNode(false);
+ }
+
+ @Override
+ @Inject(fromContext = FromContext.NAME)
+ public void setServiceHAName(String haName)
+ {
+ super.setServiceHAName(haName);
+ }
+
+ // -------------------------------------------------------------- Protected
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return an inner class that allows us to avoid exposing RPC methods as
+ * public methods of this class
+ */
+ @Override
+ protected HAServiceRpcHandler<HAServiceEvent> getRpcHandler()
+ {
+ return this.rpcHandler;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @returns the key used by DRM and the partition rpc handler mapping.
+ */
+ @Override
+ public String getHAServiceKey()
+ {
+ String name = this.getServiceHAName();
+
+ return ((this.domain != null) && this.masterPerDomain) ? name +
":" + this.domain : name;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return a {@link ModClusterServiceDRMEntry}
+ */
+ @Override
+ protected Serializable getReplicant()
+ {
+ return this.drmEntry;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return a list of cluster nodes from which to elect a new master
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ protected List<ClusterNode> getElectionCandidates()
+ {
+ List<ModClusterServiceDRMEntry> candidates =
this.getHAPartition().getDistributedReplicantManager().lookupReplicants(this.getHAServiceKey());
+
+ return this.narrowCandidateList(candidates);
+ }
+
+ /**
+ * Processes the candidate list, discarding those who don't match our domain nor
the best
+ * candidate when it comes to the ability to communicate with proxies.
+ *
+ * @param candidates the universe of possible candidates.
+ * @return a list of candidates with an equivalent ability to communicate
+ * with proxies, or <code>null</code> if
<code>candidates</code>
+ * is <code>null</code>.
+ */
+ List<ClusterNode>
narrowCandidateList(Collection<ModClusterServiceDRMEntry> candidates)
+ {
+ if (candidates == null) return null;
+
+ List<ClusterNode> narrowed = new
ArrayList<ClusterNode>(candidates.size());
+ ModClusterServiceDRMEntry champion = null;
+
+ for (ModClusterServiceDRMEntry candidate : candidates)
+ {
+ if (champion == null)
+ {
+ champion = candidate;
+ narrowed.add(candidate.getPeer());
+ }
+ else
+ {
+ int compFactor = candidate.compareTo(champion);
+ if (compFactor < 0)
+ {
+ // New champ
+ narrowed.clear();
+ champion = candidate;
+ narrowed.add(candidate.getPeer());
+ }
+ else if (compFactor == 0)
+ {
+ // As good as our champ
+ narrowed.add(candidate.getPeer());
+ }
+ // else candidate didn't make the cut; continue
+ }
+ }
+
+ return narrowed;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void updateClusterStatus()
+ {
+ this.localHandler.status();
+ Set<MCMPServerState> masterList = null;
+ Map<ClusterNode, MCMPServerDiscoveryEvent> latestEvents = null;
+ synchronized (this.proxyChangeDigest)
+ {
+ masterList = this.localHandler.getProxyStates();
+ latestEvents = new HashMap<ClusterNode,
MCMPServerDiscoveryEvent>(this.proxyChangeDigest);
+ }
+ HAPartition partition = this.getHAPartition();
+ List<ModClusterServiceDRMEntry> replicants =
partition.getDistributedReplicantManager().lookupReplicants(this.getHAServiceKey());
+ Map<ClusterNode, ModClusterServiceDRMEntry> nonresponsive = new
HashMap<ClusterNode, ModClusterServiceDRMEntry>();
+ for (ModClusterServiceDRMEntry replicant : replicants)
+ {
+ nonresponsive.put(replicant.getPeer(), replicant);
+ }
+ nonresponsive.remove(partition.getClusterNode());
+
+ // FIXME -- what about our own dropped discovery events if we just became master?
+ List responses = this.getClusterCoordinatorState(masterList);
+
+ // Gather up all the reset requests in one list
+ // FIXME -- what about our own dropped requests if we just became master?
+ List<MCMPRequest> resetRequests = new ArrayList<MCMPRequest>();
+
+ // Gather all the load balance factors
+ Map<String, Integer> loadBalanceFactors = new HashMap<String,
Integer>();
+
+ // Gather the info on who knows about what proxies
+ Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses = new
HashMap<ClusterNode, PeerMCMPDiscoveryStatus>();
+
+ boolean resync = false;
+ for (Object response : responses)
+ {
+ if (response instanceof ModClusterServiceStateGroupRpcResponse)
+ {
+ ModClusterServiceStateGroupRpcResponse mcssgrr =
(ModClusterServiceStateGroupRpcResponse) response;
+ ClusterNode cn = mcssgrr.getSender();
+
+ // Check for discovery events we haven't processed
+ MCMPServerDiscoveryEvent latestEvent = latestEvents.get(cn);
+ for (MCMPServerDiscoveryEvent toCheck : mcssgrr.getUnacknowledgedEvents())
+ {
+ if (latestEvent != null && latestEvent.getEventIndex() <=
toCheck.getEventIndex())
+ {
+ continue; // already processed it
+ }
+
+ AddressPort ap = toCheck.getMCMPServer();
+ if (toCheck.isAddition())
+ {
+ this.localHandler.addProxy(ap.getAddress(), ap.getPort());
+ }
+ else
+ {
+ this.localHandler.removeProxy(ap.getAddress(), ap.getPort());
+ }
+ resync = true;
+ }
+
+ if (!resync) // don't bother if we are going to start over
+ {
+ statuses.put(cn, new PeerMCMPDiscoveryStatus(cn, mcssgrr.getStates(),
latestEvent));
+
+ List<MCMPRequest> toAdd = mcssgrr.getResetRequests();
+ if (toAdd != null)
+ {
+ resetRequests.addAll(toAdd);
+ }
+
+ ModClusterServiceDRMEntry removed = nonresponsive.remove(cn);
+ if (removed != null)
+ {
+ Integer lbf = new Integer(mcssgrr.getLoadBalanceFactor());
+ for (String jvmRoute : removed.getJvmRoutes())
+ {
+ loadBalanceFactors.put(jvmRoute, lbf);
+ }
+ }
+ }
+ }
+ else if (response instanceof ThrowableGroupRpcResponse)
+ {
+ ThrowableGroupRpcResponse tgrr = (ThrowableGroupRpcResponse) response;
+ ClusterNode cn = tgrr.getSender();
+
+ this.log.warn(this.sm.getString("modcluster.error.rpc.known",
"getClusterCoordinatorState", cn), tgrr.getValue());
+
+ // Don't remove from nonresponsive list and we'll pass back an error
+ // status (null server list) to this peer
+ }
+ else if (response instanceof Throwable)
+ {
+ this.log.warn(this.sm.getString("modcluster.error.rpc.unknown",
"getClusterCoordinatorState"), (Throwable) response);
+ }
+ else
+ {
+ this.log.error(this.sm.getString("modcluster.error.rpc.unexpected",
response, "getClusterCoordinatorState"));
+ }
+ }
+
+ if (resync)
+ {
+ // We picked up previously unknown discovery events; start over
+ this.updateClusterStatus();
+ return;
+ }
+
+ // Add error-state objects for non-responsive peers
+ Integer lbf = new Integer(0);
+ for (Map.Entry<ClusterNode, ModClusterServiceDRMEntry> entry :
nonresponsive.entrySet())
+ {
+ ClusterNode cn = entry.getKey();
+ statuses.put(entry.getKey(), new PeerMCMPDiscoveryStatus(cn, null,
latestEvents.get(cn)));
+
+ for (String jvmRoute : entry.getValue().getJvmRoutes())
+ {
+ loadBalanceFactors.put(jvmRoute, lbf);
+ }
+ }
+
+ // FIXME handle crashed members, gone from DRM
+
+ // Advise the proxies of any reset requests
+ this.localHandler.sendRequests(resetRequests);
+
+ // Pass along the LBF values
+ List<MCMPRequest> statusRequests = new ArrayList<MCMPRequest>();
+ for (Map.Entry<String, Integer> entry : loadBalanceFactors.entrySet())
+ {
+ statusRequests.add(MCMPUtils.createStatusRequest(entry.getKey(),
entry.getValue().intValue()));
+ }
+ this.localHandler.sendRequests(statusRequests);
+
+ // Advise the members the process is done and that they should update DRM
+ this.notifyClusterStatusComplete(masterList, statuses);
+ }
+
+ private void notifyClusterStatusComplete(Set<MCMPServerState> masterList,
+ Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses)
+ {
+ HAPartition partition = this.getHAPartition();
+
+ // Determine who should update DRM first -- us or the rest of the nodes
+ Set<ModClusterServiceDRMEntry> allStatuses = new
HashSet<ModClusterServiceDRMEntry>(statuses.values());
+ ModClusterServiceDRMEntry ourCurrentStatus = (ModClusterServiceDRMEntry)
partition.getDistributedReplicantManager().lookupLocalReplicant(this.getHAServiceKey());
+ allStatuses.add(ourCurrentStatus);
+
+ boolean othersFirst =
this.narrowCandidateList(allStatuses).contains(partition.getClusterNode());
+ ModClusterServiceDRMEntry ourNewStatus = new
ModClusterServiceDRMEntry(partition.getClusterNode(), masterList);
+ boolean updated = (ourNewStatus.equals(ourCurrentStatus) == false);
+
+ if (othersFirst)
+ {
+ this.clusterStatusComplete(statuses);
+
+ if (updated)
+ {
+ this.updateLocalDRM(ourNewStatus);
+ }
+ }
+ else
+ {
+ if (updated)
+ {
+ this.updateLocalDRM(ourNewStatus);
+ }
+
+ this.clusterStatusComplete(statuses);
+ }
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ModClusterServiceRpcHandler#clusterStatusComplete(java.util.Map)
+ */
+ public void clusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus>
statuses)
+ {
+ try
+ {
+ this.callMethodOnPartition("clusterStatusComplete", new Object[] {
statuses }, CLUSTER_STATUS_COMPLETE_TYPES);
+ }
+ catch (Exception e)
+ {
+ this.log.error(this.sm.getString("modcluster.error.status.complete"),
e);
+ }
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ModClusterServiceRpcHandler#getClusterCoordinatorState(java.util.Set)
+ */
+ public List<?> getClusterCoordinatorState(Set<MCMPServerState>
masterList)
+ {
+ try
+ {
+ return this.callMethodOnPartition("getClusterCoordinatorState", new
Object[] { masterList }, GET_CLUSTER_COORDINATOR_STATE_TYPES);
+ }
+ catch (Exception e)
+ {
+ throw Utils.convertToUnchecked(e);
+ }
+ }
+
+ private void updateLocalDRM(ModClusterServiceDRMEntry ourNewStatus) throws Error
+ {
+ try
+ {
+
this.getHAPartition().getDistributedReplicantManager().add(this.getHAServiceKey(),
ourNewStatus);
+ }
+ catch (Exception e)
+ {
+ throw Utils.convertToUnchecked(e);
+ }
+ }
+
+ // ---------------------------------------------------------- Inner classes
+
+ /**
+ * This is the object that gets invoked on via reflection by HAPartition.
+ */
+ protected class RpcHandler extends HAServiceImpl<HAServiceEvent>.RpcHandler
implements ModClusterServiceRpcHandler<GroupRpcResponse, MCMPServer>,
ClusteredMCMPHandlerRpcHandler, ResetRequestSourceRpcHandler<GroupRpcResponse>
+ {
+ private final ModClusterService coord = ModClusterService.this;
+ private final GroupRpcResponse SUCCESS = new
GroupRpcResponse(this.coord.getHAPartition().getClusterNode());
+/*
+ public GroupRpcResponse getLocalAddress() throws IOException
+ {
+ if (this.coord.isMasterNode())
+ {
+ return new
InetAddressGroupRpcResponse(this.coord.getHAPartition().getClusterNode(),
+
this.coord.localHandler.getLocalAddress());
+ }
+
+ return null;
+ }
+*/
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#mcmpServerDiscoveryEvent(org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent)
+ */
+ public GroupRpcResponse mcmpServerDiscoveryEvent(MCMPServerDiscoveryEvent event)
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ synchronized (ModClusterService.this.proxyChangeDigest)
+ {
+ AddressPort ap = event.getMCMPServer();
+
+ if (event.isAddition())
+ {
+ this.coord.localHandler.addProxy(ap.getAddress(), ap.getPort());
+ }
+ else
+ {
+ this.coord.localHandler.removeProxy(ap.getAddress(), ap.getPort());
+ }
+
+ ModClusterService.this.proxyChangeDigest.put(event.getSender(), event);
+
+ return new
GroupRpcResponse(ModClusterService.this.getHAPartition().getClusterNode());
+ }
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ModClusterServiceRpcHandler#getClusterCoordinatorState(java.util.Set)
+ */
+ public GroupRpcResponse getClusterCoordinatorState(Set<MCMPServer>
masterList)
+ {
+ // TODO is this the correct response here?
+ if (this.coord.isMasterNode()) return null;
+
+ Set<MCMPServerState> ourStates =
this.coord.clusteredHandler.updateServersFromMasterNode(masterList);
+
+ boolean needReset = this.coord.clusteredHandler.getNeedsResetTransmission();
+
+ List<MCMPRequest> resetRequests = needReset ?
this.coord.resetRequestSource.getLocalResetRequests() : null;
+
+ ClusterNode node = ModClusterService.this.getHAPartition().getClusterNode();
+ List<MCMPServerDiscoveryEvent> events =
this.coord.clusteredHandler.getPendingDiscoveryEvents();
+
+ GroupRpcResponse response = new ModClusterServiceStateGroupRpcResponse(node,
this.coord.latestLoad, ourStates, events, resetRequests);
+
+ if (needReset)
+ {
+ this.coord.clusteredHandler.recordResetTransmission();
+ }
+
+ return response;
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ModClusterServiceRpcHandler#clusterStatusComplete(java.util.Map)
+ */
+ public void clusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus>
statuses)
+ {
+ HAPartition partition = this.coord.getHAPartition();
+ ClusterNode cn = partition.getClusterNode();
+ PeerMCMPDiscoveryStatus newStatus = statuses.get(cn);
+ if (newStatus != null)
+ {
+ // Notify our handler that discovery events have been processed
+
this.coord.clusteredHandler.discoveryEventsReceived(newStatus.getLatestDiscoveryEvent());
+
+ // Notify our handler that any reset requests have been processed
+ this.coord.clusteredHandler.recordResetSuccess();
+
+ DistributedReplicantManager drm =
partition.getDistributedReplicantManager();
+ String key = this.coord.getHAServiceKey();
+ ModClusterServiceDRMEntry oldStatus = (ModClusterServiceDRMEntry)
drm.lookupLocalReplicant(key);
+ if (newStatus.equals(oldStatus) == false)
+ {
+ try
+ {
+ drm.add(key, new ModClusterServiceDRMEntry(cn,
newStatus.getMCMPServerStates()));
+ }
+ catch (Exception e)
+ {
+
this.coord.log.error(ModClusterService.this.sm.getString("modcluster.error.drm"),
e);
+ }
+ }
+ }
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#getProxyConfiguration()
+ */
+ public GroupRpcResponse getProxyConfiguration()
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ ClusterNode node = ModClusterService.this.getHAPartition().getClusterNode();
+ String configuration = this.coord.localHandler.getProxyConfiguration();
+
+ return new StringGroupRpcResponse(node, configuration);
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#isProxyHealthOK()
+ */
+ public GroupRpcResponse isProxyHealthOK()
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ ClusterNode node = ModClusterService.this.getHAPartition().getClusterNode();
+ boolean ok = this.coord.localHandler.isProxyHealthOK();
+
+ return new BooleanGroupRpcResponse(node, ok);
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#markProxiesInError()
+ */
+ public GroupRpcResponse markProxiesInError()
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ this.coord.localHandler.markProxiesInError();
+
+ return this.SUCCESS;
+ }
+
+ /**
+ * @see org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#reset()
+ */
+ public GroupRpcResponse reset()
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ this.coord.localHandler.reset();
+
+ return this.SUCCESS;
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequest(org.jboss.modcluster.mcmp.MCMPRequest)
+ */
+ public GroupRpcResponse sendRequest(MCMPRequest request)
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ this.coord.localHandler.sendRequest(request);
+
+ return this.SUCCESS;
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequests(java.util.List)
+ */
+ public GroupRpcResponse sendRequests(List<MCMPRequest> requests)
+ {
+ if (!this.coord.isMasterNode()) return null;
+
+ this.coord.localHandler.sendRequests(requests);
+
+ return this.SUCCESS;
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ResetRequestSourceRpcHandler#getResetRequests()
+ */
+ public GroupRpcResponse getResetRequests()
+ {
+ ClusterNode node = ModClusterService.this.getHAPartition().getClusterNode();
+ List<MCMPRequest> requests =
this.coord.resetRequestSource.getLocalResetRequests();
+
+ return new ResetRequestGroupRpcResponse(node, requests);
+ }
+ }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterServiceMBean.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterServiceMBean.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ModClusterServiceMBean.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,81 @@
+/*
+ * 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.modcluster;
+
+import org.jboss.modcluster.mcmp.MCMPRequestType;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+
+/**
+ * StandardMBean interface for {@link ModClusterService}.
+ *
+ * @author Brian Stansberry
+ */
+public interface ModClusterServiceMBean
+{
+ /**
+ * Add a proxy to the list of those with which this handler communicates.
+ * Communication does not begin until the next call to {@link #status()}.
+ *
+ * @param host the hostname of the proxy; a string suitable for passing to
+ * <code>InetAddress.getByHost(...)</code>
+ * @param port the port on which the proxy listens for MCMP requests
+ */
+ void addProxy(String host, int port);
+
+ /**
+ * Remove a proxy from the list of those with which this handler communicates.
+ * Communication does not end until the next call to {@link #status()}.
+ *
+ * @param host the hostname of the proxy; a string suitable for passing to
+ * <code>InetAddress.getByHost(...)</code>
+ * @param port the port on which the proxy listens for MCMP requests
+ */
+ void removeProxy(String host, int port);
+
+ /**
+ * Reset any proxies whose status is {@link MCMPServerState#DOWN DOWN} up to
+ * {@link MCMPServerState#ERROR ERROR}, where the configuration will
+ * be refreshed.
+ */
+ void reset();
+
+ /**
+ * FIXME. This is the same as markProxiesInError().
+ *
+ * Reset any proxies whose status is {@link MCMPServerState#OK OK} down to
+ * {@link MCMPServerState#ERROR ERROR}, which will trigger a refresh of
+ * their configuration. To be used through JMX or similar.
+ */
+ void refresh();
+
+ /**
+ * Sends a {@link MCMPRequestType#DUMP DUMP} request to all proxies,
+ * concatentating their responses into a single string.
+ *
+ * TODO wouldn't a List<String> be better? Let the caller concatenate if
+ * so desired.
+ *
+ * @return the configuration information from all the accessible proxies.
+ */
+ String getProxyConfiguration();
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/Utils.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/Utils.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/Utils.java 2008-09-03 19:37:13
UTC (rev 1774)
@@ -0,0 +1,152 @@
+package org.jboss.modcluster;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+
+public class Utils
+{
+ private static final Logger log = Logger.getLogger(Utils.class);
+ private static final StringManager sm = StringManager.getManager(Constants.Package);
+
+ /**
+ * Find the most likely connector the proxy server should connect to, or
+ * accept connections from.
+ *
+ * @param connectors
+ * @return
+ */
+ public static Connector findProxyConnector(Connector[] connectors)
+ {
+ int pos = 0;
+ int maxThreads = 0;
+ for (int i = 0; i < connectors.length; i++) {
+ if (connectors[i].getProtocol().startsWith("AJP")) {
+ // Return any AJP connector found
+ return connectors[i];
+ }
+ if
(Boolean.TRUE.equals(IntrospectionUtils.getProperty(connectors[i].getProtocolHandler(),
"reverseConnection"))) {
+ return connectors[i];
+ }
+ Integer mt = (Integer)
IntrospectionUtils.getProperty(connectors[i].getProtocolHandler(),
"maxThreads");
+ if (mt.intValue() > maxThreads) {
+ maxThreads = mt.intValue();
+ pos = i;
+ }
+ }
+ // If no AJP connector and no reverse, return the connector with the most threads
+ return connectors[pos];
+ }
+
+ /**
+ * Return the address on which the connector is bound.
+ *
+ * @param connector
+ * @return
+ */
+ public static String getAddress(Connector connector)
+ {
+ InetAddress inetAddress =
+ (InetAddress) IntrospectionUtils.getProperty(connector.getProtocolHandler(),
"address");
+ if (inetAddress == null) {
+ // Should not happen
+ return "127.0.0.1";
+ } else {
+ return inetAddress.getHostAddress();
+ }
+ }
+
+ /**
+ * Return the JvmRoute for the specified context.
+ *
+ * @param context
+ * @return
+ */
+ public static String getJvmRoute(Context context)
+ {
+ return ((Engine) context.getParent().getParent()).getJvmRoute();
+ }
+
+ /**
+ * Return the host and its alias list with which the context is associated.
+ *
+ * @param context
+ * @return
+ */
+ public static String getHost(Context context)
+ {
+ StringBuffer result = new StringBuffer();
+ Host host = (Host) context.getParent();
+ result.append(host.getName());
+ String[] aliases = host.findAliases();
+ for (int i = 0; i < aliases.length; i++) {
+ result.append(',');
+ result.append(aliases[i]);
+ }
+ return result.toString();
+ }
+
+ public static void establishJvmRouteAndConnectorAddress(Engine engine, MCMPHandler
mcmpHandler) throws IOException
+ {
+ Connector connector = findProxyConnector(engine.getService().findConnectors());
+ InetAddress localAddress =
+ (InetAddress) IntrospectionUtils.getProperty(connector.getProtocolHandler(),
"address");
+ if ((engine.getJvmRoute() == null || localAddress == null) &&
mcmpHandler.getProxyStates().size() > 0) {
+ // Automagical JVM route (address + port + engineName)
+ if (localAddress == null) {
+ localAddress = mcmpHandler.getLocalAddress();
+ if (localAddress != null) {
+ IntrospectionUtils.setProperty(connector.getProtocolHandler(),
"address", localAddress.getHostAddress());
+ } else {
+ // Should not happen
+ IntrospectionUtils.setProperty(connector.getProtocolHandler(),
"address", "127.0.0.1");
+ }
+ log.info(sm.getString("modcluster.util.address",
localAddress.getHostAddress()));
+ }
+ if (engine.getJvmRoute() == null) {
+ String hostName = null;
+ if (localAddress != null) {
+ hostName = localAddress.getHostName();
+ } else {
+ // Fallback
+ hostName = "127.0.0.1";
+ }
+ String jvmRoute = hostName + ":" + connector.getPort() +
":" + engine.getName();
+ engine.setJvmRoute(jvmRoute);
+ log.info(sm.getString("modcluster.util.jvmRoute",
engine.getName(), jvmRoute));
+ }
+ }
+ }
+
+ /**
+ * Analyzes the type of the given Throwable, handing it back if it is a
+ * RuntimeException, wrapping it in a RuntimeException if it is a checked
+ * exception, or throwing it if it is an Error
+ *
+ * @param t the throwable
+ * @return a RuntimeException based on t
+ * @throws Error if t is an Error
+ */
+ public static RuntimeException convertToUnchecked(Throwable t) throws Error
+ {
+ if (t instanceof Error)
+ throw (Error) t;
+ else if (t instanceof RuntimeException)
+ return (RuntimeException) t;
+ else
+ return new RuntimeException(t.getMessage(), t);
+ }
+
+ private Utils()
+ {
+ }
+
+}
\ No newline at end of file
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseEventType.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseEventType.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseEventType.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright(c) 2008 Red Hat Middleware, LLC,
+ * and individual contributors as indicated by the @authors tag.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ */
+
+package org.jboss.modcluster.advertise;
+
+/**
+ * Set what type of event the AdvertiseEvent signals.
+ * @param type The type of event. One of:
+ * <PRE>
+ * ON_NEW_SERVER -- New AdvertisedServer detected
+ * ON_STATUS_CHANGE -- AdvertisedServer server changed status
+ * </PRE>
+ */
+public enum AdvertiseEventType
+{
+ /** New AdvertisedServer detected */
+ ON_NEW_SERVER( 0),
+ /** AdvertisedServer server changed status */
+ ON_STATUS_CHANGE( 1);
+
+ private int value;
+ private AdvertiseEventType(int v)
+ {
+ value = v;
+ }
+
+ public int valueOf()
+ {
+ return value;
+ }
+
+ public static AdvertiseEventType valueOf(int value)
+ {
+ for (AdvertiseEventType e : values()) {
+ if (e.value == value)
+ return e;
+ }
+ throw new IllegalArgumentException("Invalid initializer: " + value);
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseListener.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseListener.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertiseListener.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,479 @@
+/*
+ *
+ * Copyright(c) 2008 Red Hat Middleware, LLC,
+ * and individual contributors as indicated by the @authors tag.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ */
+
+package org.jboss.modcluster.advertise;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.apache.catalina.util.StringManager;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.Constants;
+
+
+/** AdvertiseListener
+ * Listens for Advertise messages from mod_cluster
+ *
+ * @author Mladen Turk
+ *
+ */
+public class AdvertiseListener
+{
+ /** Default port for listening Advertise messages.
+ */
+ public static int DEFAULT_PORT = 23364;
+ /** Default Multicast group address for listening Advertise messages.
+ */
+ public static String DEFAULT_GROUP = "224.0.1.105";
+
+ private static final Logger log = Logger.getLogger(AdvertiseListener.class);
+
+ private static String RFC_822_FMT = "EEE, d MMM yyyy HH:mm:ss Z";
+ private int advertisePort = DEFAULT_PORT;
+ private String groupAddress = DEFAULT_GROUP;
+ private MulticastSocket ms;
+ private SimpleDateFormat df;
+ private boolean listening = true;
+ private boolean initialized = false;
+ private boolean running = false;
+ private boolean paused = false;
+ private boolean daemon = true;
+ private byte [] secure = new byte[16];
+ private String securityKey = null;
+ private MessageDigest md = null;
+
+ private HashMap<String, AdvertisedServer> servers;
+
+ private MCMPHandler commHandler;
+ private Thread workerThread;
+
+ /**
+ * The string manager for this package.
+ */
+ private StringManager sm = StringManager.getManager(Constants.Package);
+
+
+ private static void digestString(MessageDigest md, String s)
+ {
+ int len = s.length();
+ byte [] b = new byte[len];
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (c < 127)
+ b[i] = (byte)c;
+ else
+ b[i] = '?';
+ }
+ md.update(b);
+ }
+
+ /** Create AdvertiseListener instance
+ * @param eventHandler The event handler that will be used for
+ * status and new server notifications.
+ */
+ public AdvertiseListener(MCMPHandler commHandler)
+ {
+ df = new SimpleDateFormat(RFC_822_FMT, Locale.US);
+ servers = new HashMap<String, AdvertisedServer>();
+ this.commHandler = commHandler;
+
+ MCMPHandlerConfiguration config = commHandler.getConfiguration();
+
+ if (config.getAdvertiseGroupAddress() != null) {
+ setGroupAddress(config.getAdvertiseGroupAddress());
+ }
+ if (config.getAdvertisePort() > 0) {
+ setAdvertisePort(config.getAdvertisePort());
+ }
+ try {
+ if (config.getAdvertiseSecurityKey() != null) {
+ setSecurityKey(config.getAdvertiseSecurityKey());
+ }
+ start();
+ } catch (IOException e) {
+ log.error(sm.getString("modcluster.error.startListener"), e);
+ } catch (NoSuchAlgorithmException e) {
+ // Should never happen
+ log.error(sm.getString("modcluster.error.startListener"), e);
+ }
+ }
+
+ /**
+ * The default is true - the control thread will be
+ * in daemon mode. If set to false, the control thread
+ * will not be daemon - and will keep the process alive.
+ */
+ public void setDaemon(boolean b)
+ {
+ daemon = b;
+ }
+
+ public boolean getDaemon()
+ {
+ return daemon;
+ }
+
+ /** Set Advertise security key
+ * @param key The key to use.<br/>
+ * Security key must match the AdvertiseKey
+ * on the advertised server.
+ */
+ public void setSecurityKey(String key)
+ throws NoSuchAlgorithmException
+ {
+ securityKey = key;
+ if (md == null)
+ md = MessageDigest.getInstance("MD5");
+ }
+
+ /** Set Advertise port
+ * @param port The UDP port to use.
+ */
+ public void setAdvertisePort(int port)
+ {
+ advertisePort = port;
+ }
+
+ public int getAdvertisePort()
+ {
+ return advertisePort;
+ }
+
+ /** Set Advertise Multicaset group address
+ * @param address The IP or host address to use.
+ */
+ public void setGroupAddress(String address)
+ {
+ groupAddress = address;
+ }
+
+ /** Get Advertise Multicaset group address
+ */
+ public String getGroupAddress()
+ {
+ return groupAddress;
+ }
+
+ /** Get Collection of all AdvertisedServer instances.
+ */
+ public Collection<AdvertisedServer> getServers()
+ {
+ return servers.values();
+ }
+
+ /** Get AdvertiseServer server.
+ * @param name Server name to get.
+ */
+ public AdvertisedServer getServer(String name)
+ {
+ return servers.get(name);
+ }
+
+ /** Remove the AdvertisedServer from the collection.
+ * @param server Server to remove.
+ */
+ public void removeServer(AdvertisedServer server)
+ {
+ servers.remove(server);
+ }
+
+ private void init()
+ throws IOException
+ {
+ ms = new MulticastSocket(advertisePort);
+ ms.setTimeToLive(16);
+ ms.joinGroup(InetAddress.getByName(groupAddress));
+ initialized = true;
+ }
+
+ private void interruptDatagramReader()
+ {
+ if (!initialized)
+ return;
+ try {
+ // Restrict to localhost.
+ ms.setTimeToLive(0);
+ DatagramPacket dp = new DatagramPacket(secure, secure.length,
+ InetAddress.getByName(groupAddress),
+ advertisePort);
+ ms.send(dp);
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
+ /** Start the Listener, creating listener thread.
+ */
+ public void start()
+ throws IOException
+ {
+ if (!initialized) {
+ init();
+ }
+ if (!running) {
+ SecureRandom random = new SecureRandom();
+ random.nextBytes(secure);
+ secure[0] = 0;
+ running = true;
+ paused = false;
+ listening = true;
+ AdvertiseListenerWorker aw = new AdvertiseListenerWorker();
+ workerThread = new Thread(aw);
+ workerThread.setDaemon(daemon);
+ workerThread.start();
+ }
+ }
+
+ /**
+ * Pause the listener, which will make it stop accepting new advertise
+ * messages.
+ */
+ public void pause()
+ {
+ if (running && !paused) {
+ paused = true;
+ interruptDatagramReader();
+ }
+ }
+
+
+ /**
+ * Resume the listener, which will make it start accepting new advertise
+ * messages again.
+ */
+ public void resume()
+ {
+ if (running && paused) {
+ // Genererate new private secure
+ SecureRandom random = new SecureRandom();
+ random.nextBytes(secure);
+ secure[0] = 0;
+ paused = false;
+ }
+ }
+
+
+ /**
+ * Stop the endpoint. This will cause all processing threads to stop.
+ */
+ public void stop()
+ {
+ if (running) {
+ running = false;
+ interruptDatagramReader();
+ workerThread = null;
+ }
+ }
+
+
+ /**
+ * Deallocate listener and close sockets.
+ */
+ public void destroy()
+ throws IOException
+ {
+ if (running) {
+ stop();
+ }
+ if (initialized) {
+ ms.leaveGroup(InetAddress.getByName(groupAddress));
+ ms.close();
+ initialized = false;
+ ms = null;
+ }
+ }
+
+ private boolean verifyDigest(String digest, String server, String date)
+ {
+ if (md == null)
+ return true;
+ md.reset();
+ digestString(md, securityKey);
+ digestString(md, date);
+ digestString(md, server);
+ byte [] our = md.digest();
+ byte [] dst = new byte[digest.length() * 2];
+ for (int i = 0, j = 0; i < digest.length(); i++) {
+ char ch = digest.charAt(i);
+ dst[j++] = (byte)((ch >= 'A') ? ((ch & 0xdf) - 'A') +
10 : (ch - '0'));
+ }
+ return true;
+ }
+
+ /**
+ * True if listener is accepting the advetise messages.<br/>
+ * If false it means that listener is experiencing some
+ * network problems if running.
+ */
+ public boolean isListening()
+ {
+ return listening;
+ }
+
+
+ // ------------------------------------ AdvertiseListenerWorker Inner Class
+ private class AdvertiseListenerWorker implements Runnable
+ {
+
+ protected AdvertiseListenerWorker()
+ {
+ // Nothing
+ }
+ /**
+ * The background thread that listens for incoming Advertise packets
+ * and hands them off to an appropriate AdvertiseEvent handler.
+ */
+ public void run() {
+ byte[] buffer = new byte[512];
+ // Loop until we receive a shutdown command
+ while (running) {
+ // Loop if endpoint is paused
+ while (paused) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ try {
+ DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
+ ms.receive(dp);
+ if (!running)
+ break;
+ byte [] data = dp.getData();
+ boolean intr = false;
+ if (dp.getLength() == secure.length) {
+ int i;
+ for (i = 0; i < secure.length; i++) {
+ if (data[i] != secure[i])
+ break;
+ }
+ if (i == secure.length)
+ intr = true;
+ }
+ if (intr)
+ continue;
+ String s = new String(data, 0, dp.getLength(), "8859_1");
+ if (!s.startsWith("HTTP/1."))
+ continue;
+
+ String [] headers = s.split("\r\n");
+ String date_str = null;
+ Date date = null;
+ int status = 0;
+ String status_desc = null;
+ String digest = null;
+ String server_name = null;
+ AdvertisedServer server = null;
+ boolean added = false;
+ for (int i = 0; i < headers.length; i++) {
+ if (i == 0) {
+ String [] sline = headers[i].split(" ", 3);
+ if (sline == null || sline.length != 3)
+ break;
+ status = Integer.parseInt(sline[1]);
+ if (status < 100)
+ break;
+ status_desc = sline[2];
+ }
+ else {
+ String [] hdrv = headers[i].split(": ", 2);
+ if (hdrv == null || hdrv.length != 2)
+ break;
+ if (hdrv[0].equals("Date")) {
+ date_str = hdrv[1];
+ try {
+ date = df.parse(date_str);
+ } catch (ParseException e) {
+ date = new Date();
+ }
+ }
+ else if (hdrv[0].equals("Digest")) {
+ digest = hdrv[1];
+ }
+ else if (hdrv[0].equals("Server")) {
+ server_name = hdrv[1];
+ server = servers.get(server_name);
+ if (server == null) {
+ server = new AdvertisedServer(server_name);
+ added = true;
+ }
+ }
+ else if (server != null) {
+ server.setParameter(hdrv[0], hdrv[1]);
+ }
+ }
+ }
+ if (server != null && status > 0) {
+ if (md != null) {
+ /* We need a digest to match */
+ if (!verifyDigest(digest, server_name, date_str)) {
+ System.out.println("Digest mismatch");
+ continue;
+ }
+ }
+ server.setDate(date);
+ boolean rc = server.setStatus(status, status_desc);
+ if (added) {
+ servers.put(server_name, server);
+ // Call the new server callback
+ //eventHandler.onEvent(AdvertiseEventType.ON_NEW_SERVER,
server);
+ String proxy =
server.getParameter(AdvertisedServer.MANAGER_ADDRESS);
+ if (proxy != null) {
+ commHandler.addProxy(proxy);
+ }
+ }
+ else if (rc) {
+ // Call the status change callback
+ //eventHandler.onEvent(AdvertiseEventType.ON_STATUS_CHANGE,
server);
+ }
+ }
+ listening = true;
+ } catch (IOException e) {
+ // Do not blow the CPU in case of communication error
+ listening = false;
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException x) {
+ // Ignore
+ }
+ }
+ }
+ }
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertisedServer.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertisedServer.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/advertise/AdvertisedServer.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,122 @@
+/*
+ *
+ * Copyright(c) 2008 Red Hat Middleware, LLC,
+ * and individual contributors as indicated by the @authors tag.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ */
+
+package org.jboss.modcluster.advertise;
+
+import java.util.Date;
+import java.util.HashMap;
+
+/**
+ * Advertised server instance
+ *
+ * @author Mladen Turk
+ *
+ */
+public class AdvertisedServer
+{
+ private String server;
+ private Date date;
+ private int status;
+ private String status_desc;
+ private HashMap<String, String> headers;
+
+ /** Manager-Address header */
+ public static String MANAGER_ADDRESS = "X-Manager-Address";
+ /** Manager-Url header */
+ public static String MANAGER_URL = "X-Manager-Url";
+ /** Manager-Protocol header */
+ public static String MANAGER_PROTOCOL = "X-Manager-Protocol";
+ /** Manager-Version header */
+ public static String MANAGER_VERSION = "X-Manager-Version";
+ /** Manager-Host header */
+ public static String MANAGER_HOST = "X-Manager-Host";
+
+ protected AdvertisedServer(String server)
+ {
+ this.server = server;
+ headers = new HashMap<String, String>();
+ }
+
+ protected boolean setStatus(int status, String desc)
+ {
+ boolean rv = false;
+ status_desc = desc;
+ if (this.status == 0 ) {
+ // First time
+ this.status = status;
+ }
+ else if (this.status != status) {
+ this.status = status;
+ rv = true;
+ }
+ return rv;
+ }
+
+ /** Set the Date of the last Advertise message
+ */
+ protected void setDate(Date date)
+ {
+ this.date = date;
+ }
+
+ /** Set the Header
+ */
+ protected void setParameter(String name, String value)
+ {
+ headers.put(name, value);
+ }
+
+ /** Get Date of the last Advertise message
+ */
+ public Date getDate()
+ {
+ return date;
+ }
+
+ /** Get Status code of the last Advertise message
+ */
+ public int getStatusCode()
+ {
+ return status;
+ }
+
+ /** Get Status description of the last Advertise message
+ */
+ public String getStatusDescription()
+ {
+ return status_desc;
+ }
+
+ /** Get Advertise parameter
+ */
+ public String getParameter(String name)
+ {
+ return headers.get(name);
+ }
+
+ public String toString()
+ {
+ return server;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/BalancerConfiguration.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/BalancerConfiguration.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/BalancerConfiguration.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,40 @@
+/*
+ * 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.modcluster.config;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public interface BalancerConfiguration
+{
+ boolean getStickySession();
+
+ boolean getStickySessionRemove();
+
+ boolean getStickySessionForce();
+
+ int getWorkerTimeout();
+
+ int getMaxAttempts();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/MCMPHandlerConfiguration.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/MCMPHandlerConfiguration.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/MCMPHandlerConfiguration.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,50 @@
+/*
+ * 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.modcluster.config;
+
+/**
+ * Configuration object for an {@link MCMPHandler}.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public interface MCMPHandlerConfiguration extends SSLConfiguration
+{
+ String getProxyList();
+
+ String getProxyURL();
+
+ int getSocketTimeout();
+
+ boolean isSsl();
+
+ Boolean getAdvertise();
+
+ String getAdvertiseGroupAddress();
+
+ int getAdvertisePort();
+
+ String getAdvertiseSecurityKey();
+
+ boolean isMasterPerDomain();
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/ModClusterConfig.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/ModClusterConfig.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/ModClusterConfig.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,352 @@
+/*
+ * 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.modcluster.config;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+/**
+ * Java bean implementing the various configuration interfaces.
+ *
+ * @author Brian Stansberry
+ */
+public class ModClusterConfig
+ implements
+ BalancerConfiguration,
+ MCMPHandlerConfiguration,
+ NodeConfiguration,
+ SSLConfiguration
+{
+
+ // ----------------------------------------------- MCMPHandlerConfiguration
+
+ /**
+ * Receive advertisements from httpd proxies (default is to use advertisements
+ * if the proxyList is not set).
+ */
+ private Boolean advertise;
+ public Boolean getAdvertise() { return this.advertise; }
+ public void setAdvertise(Boolean advertise) { this.advertise = advertise; }
+
+
+ /**
+ * Advertise group.
+ */
+ private String advertiseGroupAddress = null;
+ public String getAdvertiseGroupAddress() { return this.advertiseGroupAddress; }
+ public void setAdvertiseGroupAddress(String advertiseGroupAddress) {
this.advertiseGroupAddress = advertiseGroupAddress; }
+
+
+ /**
+ * Advertise port.
+ */
+ private int advertisePort = -1;
+ public int getAdvertisePort() { return this.advertisePort; }
+ public void setAdvertisePort(int advertisePort) { this.advertisePort = advertisePort;
}
+
+
+ /**
+ * Advertise security key.
+ */
+ private String advertiseSecurityKey = null;
+ public String getAdvertiseSecurityKey() { return this.advertiseSecurityKey; }
+ public void setAdvertiseSecurityKey(String advertiseSecurityKey) {
this.advertiseSecurityKey = advertiseSecurityKey; }
+
+
+ /**
+ * Proxy list, format "address:port,address:port".
+ */
+ private String proxyList = null;
+ public String getProxyList() { return this.proxyList; }
+ public void setProxyList(String proxyList) { this.proxyList = proxyList; }
+
+
+ /**
+ * URL prefix.
+ */
+ private String proxyURL = null;
+ public String getProxyURL() { return this.proxyURL; }
+ public void setProxyURL(String proxyURL) { this.proxyURL = proxyURL; }
+
+
+ /**
+ * Connection timeout for communication with the proxy.
+ */
+ private int socketTimeout = 20000;
+ public int getSocketTimeout() { return this.socketTimeout; }
+ public void setSocketTimeout(int socketTimeout) { this.socketTimeout = socketTimeout;
}
+
+
+ // ----------------------------------------------------- SSLConfiguration
+
+ /**
+ * SSL client cert usage to connect to the proxy.
+ */
+ private boolean ssl = false;
+ public boolean isSsl() { return this.ssl; }
+ public void setSsl(boolean ssl) { this.ssl = ssl; }
+
+
+ /**
+ * SSL ciphers.
+ */
+ private String sslCiphers = null;
+ public String getSslCiphers() { return this.sslCiphers; }
+ public void setSslCiphers(String sslCiphers) { this.sslCiphers = sslCiphers; }
+
+
+ /**
+ * SSL protocol.
+ */
+ private String sslProtocol = "TLS";
+ public String getSslProtocol() { return this.sslProtocol; }
+ public void setSslProtocol(String sslProtocol) { this.sslProtocol = sslProtocol; }
+
+
+ /**
+ * Certificate encoding algorithm.
+ */
+ private String sslCertificateEncodingAlgorithm =
KeyManagerFactory.getDefaultAlgorithm();
+ public String getSslCertificateEncodingAlgorithm() { return
this.sslCertificateEncodingAlgorithm; }
+ public void setSslCertificateEncodingAlgorithm(String sslCertificateEncodingAlgorithm)
{ this.sslCertificateEncodingAlgorithm = sslCertificateEncodingAlgorithm; }
+
+
+ /**
+ * SSL keystore.
+ */
+ private String sslKeyStore = System.getProperty("user.home") +
"/.keystore";
+ public String getSslKeyStore() { return this.sslKeyStore; }
+ public void setSslKeyStore(String sslKeyStore) { this.sslKeyStore = sslKeyStore; }
+
+
+ /**
+ * SSL keystore password.
+ */
+ private String sslKeyStorePass = "changeit";
+ public String getSslKeyStorePass() { return this.sslKeyStorePass; }
+ public void setSslKeyStorePass(String sslKeyStorePass) { this.sslKeyStorePass =
sslKeyStorePass; }
+
+
+ /**
+ * Keystore type.
+ */
+ private String sslKeyStoreType = "JKS";
+ public String getSslKeyStoreType() { return this.sslKeyStoreType; }
+ public void setSslKeyStoreType(String sslKeyStoreType) { this.sslKeyStoreType =
sslKeyStoreType; }
+
+
+ /**
+ * Keystore provider.
+ */
+ private String sslKeyStoreProvider = null;
+ public String getSslKeyStoreProvider() { return this.sslKeyStoreProvider; }
+ public void setSslKeyStoreProvider(String sslKeyStoreProvider) {
this.sslKeyStoreProvider = sslKeyStoreProvider; }
+
+
+ /**
+ * Truststore algorithm.
+ */
+ private String sslTrustAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+ public String getSslTrustAlgorithm() { return this.sslTrustAlgorithm; }
+ public void setSslTrustAlgorithm(String sslTrustAlgorithm) { this.sslTrustAlgorithm =
sslTrustAlgorithm; }
+
+
+ /**
+ * Key alias.
+ */
+ private String sslKeyAlias = null;
+ public String getSslKeyAlias() { return this.sslKeyAlias; }
+ public void setSslKeyAlias(String sslKeyAlias) { this.sslKeyAlias = sslKeyAlias; }
+
+
+ /**
+ * Certificate revocation list.
+ */
+ private String sslCrlFile = null;
+ public String getSslCrlFile() { return this.sslCrlFile; }
+ public void setSslCrlFile(String sslCrlFile) { this.sslCrlFile = sslCrlFile; }
+
+
+ /**
+ * Trust max certificate length.
+ */
+ private int sslTrustMaxCertLength = 5;
+ public int getSslTrustMaxCertLength() { return this.sslTrustMaxCertLength; }
+ public void setSslTrustMaxCertLength(int sslTrustMaxCertLength) {
this.sslTrustMaxCertLength = sslTrustMaxCertLength; }
+
+
+ /**
+ * Trust store file.
+ */
+ private String sslTrustStore =
System.getProperty("javax.net.ssl.trustStore");
+ public String getSslTrustStore() { return this.sslTrustStore; }
+ public void setSslTrustStore(String sslTrustStore) { this.sslTrustStore =
sslTrustStore; }
+
+
+ /**
+ * Trust store password.
+ */
+ private String sslTrustStorePassword =
System.getProperty("javax.net.ssl.trustStorePassword");
+ public String getSslTrustStorePassword() { return this.sslTrustStorePassword; }
+ public void setSslTrustStorePassword(String sslTrustStorePassword) {
this.sslTrustStorePassword = sslTrustStorePassword; }
+
+
+ /**
+ * Trust store type.
+ */
+ private String sslTrustStoreType =
System.getProperty("javax.net.ssl.trustStoreType");
+ public String getSslTrustStoreType() { return this.sslTrustStoreType; }
+ public void setSslTrustStoreType(String sslTrustStoreType) { this.sslTrustStoreType =
sslTrustStoreType; }
+
+
+ /**
+ * Trust store provider.
+ */
+ private String sslTrustStoreProvider =
System.getProperty("javax.net.ssl.trustStoreProvider");
+ public String getSslTrustStoreProvider() { return this.sslTrustStoreProvider; }
+ public void setSslTrustStoreProvider(String sslTrustStoreProvider) {
this.sslTrustStoreProvider = sslTrustStoreProvider; }
+
+
+ // ----------------------------------------------------- NodeConfiguration
+
+
+ /**
+ * Domain parameter, which allows tying a jvmRoute to a particular domain.
+ */
+ private String domain = null;
+ public String getDomain() { return this.domain; }
+ public void setDomain(String domain) { this.domain = domain; }
+
+
+ /**
+ * Allows controlling flushing of packets.
+ */
+ private boolean flushPackets = false;
+ public boolean getFlushPackets() { return this.flushPackets; }
+ public void setFlushPackets(boolean flushPackets) { this.flushPackets = flushPackets;
}
+
+
+ /**
+ * Time to wait before flushing packets.
+ */
+ private int flushWait = -1;
+ public int getFlushWait() { return this.flushWait; }
+ public void setFlushWait(int flushWait) { this.flushWait = flushWait; }
+
+
+ /**
+ * Time to wait for a pong answer to a ping.
+ */
+ private int ping = -1;
+ public int getPing() { return this.ping; }
+ public void setPing(int ping) { this.ping = ping; }
+
+
+ /**
+ * Soft maximum inactive connection count.
+ */
+ private int smax = -1;
+ public int getSmax() { return this.smax; }
+ public void setSmax(int smax) { this.smax = smax; }
+
+
+ /**
+ * Maximum time on seconds for idle connections above smax.
+ */
+ private int ttl = -1;
+ public int getTtl() { return this.ttl; }
+ public void setTtl(int ttl) { this.ttl = ttl; }
+
+
+ /**
+ * Maximum time on seconds for idle connections the proxy will wait to connect to the
node.
+ */
+ private int nodeTimeout = -1;
+ public int getNodeTimeout() { return this.nodeTimeout; }
+ public void setNodeTimeout(int nodeTimeout) { this.nodeTimeout = nodeTimeout; }
+
+
+ /**
+ * Name of the balancer.
+ */
+ private String balancer = null;
+ public String getBalancer() { return this.balancer; }
+ public void setBalancer(String balancer) { this.balancer = balancer; }
+
+ /**
+ * Our load balance factor
+ */
+ private int loadBalanceFactor = 1;
+ public int getLoadBalanceFactor() { return this.loadBalanceFactor; }
+ public void setLoadBalanceFactor(int loadBalanceFactor)
+ {
+ assert loadBalanceFactor >= 0 : "loadBalanceFactor is negative";
+ this.loadBalanceFactor = loadBalanceFactor;
+ }
+
+
+ // ------------------------------------------------- BalancerConfiguration
+
+ /**
+ * Enables sticky sessions.
+ */
+ private boolean stickySession = true;
+ public boolean getStickySession() { return this.stickySession; }
+ public void setStickySession(boolean stickySession) { this.stickySession =
stickySession; }
+
+
+ /**
+ * Remove session when the request cannot be routed to the right node.
+ */
+ private boolean stickySessionRemove = false;
+ public boolean getStickySessionRemove() { return this.stickySessionRemove; }
+ public void setStickySessionRemove(boolean stickySessionRemove) {
this.stickySessionRemove = stickySessionRemove; }
+
+
+ /**
+ * Return an error when the request cannot be routed to the right node.
+ */
+ private boolean stickySessionForce = true;
+ public boolean getStickySessionForce() { return this.stickySessionForce; }
+ public void setStickySessionForce(boolean stickySessionForce) {
this.stickySessionForce = stickySessionForce; }
+
+
+ /**
+ * Timeout to wait for an available worker (default is no wait).
+ */
+ private int workerTimeout = -1;
+ public int getWorkerTimeout() { return this.workerTimeout; }
+ public void setWorkerTimeout(int workerTimeout) { this.workerTimeout = workerTimeout;
}
+
+
+ /**
+ * Maximum number of attempts to send the request to the backend server.
+ */
+ private int maxAttempts = -1;
+ public int getMaxAttempts() { return this.maxAttempts; }
+ public void setMaxAttempts(int maxAttempts) { this.maxAttempts = maxAttempts; }
+
+ private boolean servicePerDomain = false;
+ public boolean isMasterPerDomain() { return this.servicePerDomain; }
+ public void setServicePerDomain(boolean servicePerDomain) { this.servicePerDomain =
servicePerDomain; }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/NodeConfiguration.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/NodeConfiguration.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/NodeConfiguration.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,47 @@
+/*
+ * 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.modcluster.config;
+
+public interface NodeConfiguration
+{
+ int getSocketTimeout();
+
+ String getDomain();
+
+ boolean getFlushPackets();
+
+ int getFlushWait();
+
+ int getPing();
+
+ int getSmax();
+
+ int getTtl();
+
+ int getNodeTimeout();
+
+ String getBalancer();
+
+ int getLoadBalanceFactor();
+
+}
\ No newline at end of file
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/SSLConfiguration.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/SSLConfiguration.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/config/SSLConfiguration.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.config;
+
+/**
+ * A SSLConfiguration.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public interface SSLConfiguration
+{
+ String getSslCiphers();
+ String getSslProtocol();
+ String getSslCertificateEncodingAlgorithm();
+ String getSslKeyStore();
+ String getSslKeyStorePass();
+ String getSslKeyStoreType();
+ String getSslKeyStoreProvider();
+ String getSslTrustAlgorithm();
+ String getSslKeyAlias();
+ String getSslCrlFile();
+ int getSslTrustMaxCertLength();
+ String getSslTrustStore();
+ String getSslTrustStorePassword();
+ String getSslTrustStoreType();
+ String getSslTrustStoreProvider();
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandler.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,55 @@
+/*
+ * 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.modcluster.ha;
+
+import java.util.List;
+import java.util.Set;
+
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.mcmp.MCMPServer;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+import org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
+
+/**
+ * @author Brian Stansberry
+ */
+public interface ClusteredMCMPHandler extends MCMPHandler
+{
+ public static final String HA_SERVICE_NAME = "ModClusterService";
+
+ List<MCMPServerDiscoveryEvent> getPendingDiscoveryEvents();
+ void discoveryEventsReceived(MCMPServerDiscoveryEvent lastReceived);
+
+ Set<MCMPServerState> updateServersFromMasterNode(Set<MCMPServer>
masterList);
+
+ boolean getNeedsResetTransmission();
+ void recordResetTransmission();
+ void recordResetSuccess();
+
+ boolean isMasterNode();
+ void setMasterNode(boolean master);
+
+ String getHAServiceName();
+
+ String getPartitionName();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerImpl.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerImpl.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerImpl.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,609 @@
+/*
+ * 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.modcluster.ha;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import net.jcip.annotations.GuardedBy;
+
+import org.apache.catalina.util.StringManager;
+import org.jboss.ha.framework.interfaces.HAServiceKeyProvider;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+import org.jboss.modcluster.mcmp.AbstractMCMPHandler;
+import org.jboss.modcluster.mcmp.AddressPort;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPServer;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+import org.jboss.modcluster.Constants;
+import org.jboss.modcluster.Utils;
+import org.jboss.modcluster.ha.rpc.BooleanGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler;
+import org.jboss.modcluster.ha.rpc.GroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.GroupRpcResponseFilter;
+import org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
+import org.jboss.modcluster.ha.rpc.StringGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.ThrowableGroupRpcResponse;
+
+public class ClusteredMCMPHandlerImpl extends AbstractMCMPHandler implements
ClusteredMCMPHandler
+{
+ static final Object[] NULL_ARGS = new Object[0];
+ static final Class<?>[] NULL_TYPES = new Class[0];
+ static final Class<?>[] MCMPREQ_TYPES = new Class[] { MCMPRequest.class };
+ static final Class<?>[] MCMPREQS_TYPES = new Class[] { List.class };
+ static final Class<?>[] DISC_EVENT_TYPES = new Class[] {
MCMPServerDiscoveryEvent.class };
+
+ static final Logger log = Logger.getLogger(ClusteredMCMPHandlerImpl.class);
+
+ final HAServiceKeyProvider serviceKeyProvider;
+ private final MCMPHandler localHandler;
+ private final ClusteredMCMPHandlerRpcHandler rpcStub = new RpcStub();
+// private AdvertiseListener advertiseListener;
+
+ private volatile String haServiceName;
+ private volatile boolean masterNode = false;
+
+ @GuardedBy("errorState")
+ private final List<Boolean> errorState = new ArrayList<Boolean>();
+
+ @GuardedBy("this")
+ private List<MCMPServerDiscoveryEvent> pendingDiscoveryEvents = new
ArrayList<MCMPServerDiscoveryEvent>();
+
+ private AtomicInteger discoveryEventIndex = new AtomicInteger();
+
+ /**
+ * The string manager for this package.
+ */
+ final StringManager sm = StringManager.getManager(Constants.Package);
+
+ public ClusteredMCMPHandlerImpl(MCMPHandler localHandler, HAServiceKeyProvider
serviceKeyProvider)
+ {
+ this.localHandler = localHandler;
+ this.serviceKeyProvider = serviceKeyProvider;
+ }
+
+ // --------------------------------------------------- ClusteredMCMPHandler
+
+ public boolean isMasterNode()
+ {
+ return this.masterNode;
+ }
+
+ public void setMasterNode(boolean masterNode)
+ {
+ this.masterNode = masterNode;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.ha.ClusteredMCMPHandler#getHAServiceName()
+ */
+ public String getHAServiceName()
+ {
+ return this.haServiceName;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.ha.ClusteredMCMPHandler#setHAServiceName(java.lang.String)
+ */
+ public void setHAServiceName(String serviceName)
+ {
+ this.haServiceName = serviceName;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.ha.ClusteredMCMPHandler#getPartitionName()
+ */
+ public String getPartitionName()
+ {
+ return this.serviceKeyProvider.getHAPartition().getPartitionName();
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.ha.ClusteredMCMPHandler#getPendingDiscoveryEvents()
+ */
+ public synchronized List<MCMPServerDiscoveryEvent> getPendingDiscoveryEvents()
+ {
+ return new ArrayList<MCMPServerDiscoveryEvent>(this.pendingDiscoveryEvents);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.ha.ClusteredMCMPHandler#discoveryEventsReceived(org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent)
+ */
+ public synchronized void discoveryEventsReceived(MCMPServerDiscoveryEvent
lastReceived)
+ {
+ if (lastReceived != null)
+ {
+ for (Iterator<MCMPServerDiscoveryEvent> it =
this.pendingDiscoveryEvents.iterator(); it.hasNext();)
+ {
+ MCMPServerDiscoveryEvent event = it.next();
+ if (event.getEventIndex() <= lastReceived.getEventIndex())
+ {
+ it.remove();
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.ha.ClusteredMCMPHandler#updateServersFromMasterNode(java.util.Set)
+ */
+ public synchronized Set<MCMPServerState>
updateServersFromMasterNode(Set<MCMPServer> masterList)
+ {
+ for (MCMPServer server : masterList)
+ {
+ this.localHandler.addProxy(server.getAddress(), server.getPort(),
server.isEstablished());
+ }
+
+ for (MCMPServer server : this.localHandler.getProxyStates())
+ {
+ if (!masterList.contains(server))
+ {
+ this.localHandler.removeProxy(server.getAddress(), server.getPort());
+ }
+ }
+
+ this.localHandler.status();
+
+ return this.localHandler.getProxyStates();
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.ha.ClusteredMCMPHandler#getNeedsResetTransmission()
+ */
+ public boolean getNeedsResetTransmission()
+ {
+ synchronized (this.errorState)
+ {
+ return this.errorState.size() > 0 &&
(this.errorState.get(this.errorState.size() - 1).booleanValue() == false);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.ha.ClusteredMCMPHandler#recordResetTransmission()
+ */
+ public void recordResetTransmission()
+ {
+ synchronized (this.errorState)
+ {
+ if (this.errorState.size() > 0)
+ {
+ this.errorState.set(0, Boolean.TRUE);
+ }
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.ha.ClusteredMCMPHandler#recordResetSuccess()
+ */
+ public void recordResetSuccess()
+ {
+ synchronized (this.errorState)
+ {
+ if (this.errorState.size() > 0 || this.errorState.get(this.errorState.size()
- 1).booleanValue())
+ {
+ this.errorState.remove(0);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------ MCMPHandler
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#getConfiguration()
+ */
+ public MCMPHandlerConfiguration getConfiguration()
+ {
+ return this.localHandler.getConfiguration();
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#addProxy(java.net.InetAddress, int)
+ */
+ public synchronized void addProxy(InetAddress address, int port)
+ {
+ if (this.isMasterNode())
+ {
+ this.localHandler.addProxy(address, port);
+ }
+ else
+ {
+ this.sendDiscoveryEventToPartition(address, port, true);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#addProxy(java.net.InetAddress, int,
boolean)
+ */
+ public void addProxy(InetAddress address, int port, boolean established)
+ {
+ this.localHandler.addProxy(address, port, established);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#removeProxy(java.net.InetAddress, int)
+ */
+ public synchronized void removeProxy(InetAddress address, int port)
+ {
+ if (this.isMasterNode())
+ {
+ this.localHandler.removeProxy(address, port);
+ }
+ else
+ {
+ this.sendDiscoveryEventToPartition(address, port, false);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#getProxyStates()
+ */
+ public Set<MCMPServerState> getProxyStates()
+ {
+ return this.localHandler.getProxyStates();
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#getLocalAddress()
+ */
+ public InetAddress getLocalAddress() throws IOException
+ {
+ return this.localHandler.getLocalAddress();
+ }
+
+ public String getProxyConfiguration()
+ {
+ if (this.isMasterNode())
+ {
+ return this.localHandler.getProxyConfiguration();
+ }
+
+ GroupRpcResponse response = this.rpcStub.getProxyConfiguration();
+
+ this.validateResponse(response, false);
+
+ return ((StringGroupRpcResponse) response).getValue();
+ }
+
+ public void init(List<AddressPort> initialProxies)
+ {
+ if (this.isMasterNode())
+ {
+ this.localHandler.init(initialProxies);
+ }
+ else
+ {
+ this.localHandler.init(new ArrayList<AddressPort>());
+
+ if (initialProxies != null)
+ {
+ for (AddressPort proxy : initialProxies)
+ {
+ this.sendDiscoveryEventToPartition(proxy.getAddress(), proxy.getPort(),
true);
+ }
+ }
+ }
+ }
+
+ public boolean isProxyHealthOK()
+ {
+ if (this.isMasterNode())
+ {
+ return this.localHandler.isProxyHealthOK();
+ }
+
+ GroupRpcResponse response = this.rpcStub.isProxyHealthOK();
+
+ this.validateResponse(response, false);
+
+ return ((BooleanGroupRpcResponse) response).getValue();
+ }
+
+ public void markProxiesInError()
+ {
+ this.recordRequestFailure();
+
+ if (this.isMasterNode())
+ {
+ this.localHandler.markProxiesInError();
+ }
+ else
+ {
+ GroupRpcResponse response = this.rpcStub.markProxiesInError();
+
+ this.validateResponse(response, false);
+ }
+ }
+
+ public void reset()
+ {
+ if (this.isMasterNode())
+ {
+ this.localHandler.reset();
+ }
+ else
+ {
+ GroupRpcResponse response = this.rpcStub.reset();
+
+ this.validateResponse(response, false);
+ }
+ }
+
+ public void sendRequest(MCMPRequest request)
+ {
+ if (this.isMasterNode())
+ {
+ this.localHandler.sendRequest(request);
+ }
+ else
+ {
+ GroupRpcResponse response = this.rpcStub.sendRequest(request);
+
+ this.validateResponse(response, true);
+ }
+ }
+
+ public void sendRequests(List<MCMPRequest> requests)
+ {
+ if (this.isMasterNode())
+ {
+ this.localHandler.sendRequests(requests);
+ }
+ else
+ {
+ GroupRpcResponse response = this.rpcStub.sendRequests(requests);
+
+ this.validateResponse(response, true);
+ }
+ }
+
+ public void shutdown()
+ {
+ this.localHandler.shutdown();
+ }
+
+ public void status()
+ {
+ log.warn(this.sm.getString("modcluster.error.status.unsupported"));
+ }
+
+ // ---------------------------------------------------------------- Private
+
+ private void validateResponse(GroupRpcResponse response, boolean recordFailure)
+ {
+ if (response instanceof ThrowableGroupRpcResponse)
+ {
+ if (recordFailure)
+ {
+ this.recordRequestFailure();
+ }
+
+ throw ((ThrowableGroupRpcResponse) response).getValueAsRuntimeException();
+ }
+ }
+
+ private synchronized void sendDiscoveryEventToPartition(InetAddress address, int port,
boolean addition)
+ {
+ AddressPort ap = new AddressPort(address, port);
+ MCMPServerDiscoveryEvent event = new
MCMPServerDiscoveryEvent(this.serviceKeyProvider.getHAPartition().getClusterNode(), ap,
addition, this.discoveryEventIndex.incrementAndGet());
+ this.pendingDiscoveryEvents.add(event);
+
+ GroupRpcResponse response = this.rpcStub.mcmpServerDiscoveryEvent(event);
+
+ if (response instanceof ThrowableGroupRpcResponse)
+ {
+ // Just log it; we'll retry later
+ String msg = addition ? "modcluster.error.discovery.add" :
"modcluster.error.discovery.remove";
+ log.error(this.sm.getString(msg, address, new Integer(port)),
((ThrowableGroupRpcResponse) response).getValue());
+ }
+ }
+
+ void recordRequestFailure()
+ {
+ synchronized (this.errorState)
+ {
+ if (this.errorState.size() == 0 || this.errorState.get(this.errorState.size()
-1).booleanValue())
+ {
+ this.errorState.add(Boolean.FALSE);
+ }
+ }
+ }
+
+ class RpcStub implements ClusteredMCMPHandlerRpcHandler
+ {
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#getProxyConfiguration()
+ */
+ public GroupRpcResponse getProxyConfiguration()
+ {
+ return this.invokeRpc("getProxyConfiguration");
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#isProxyHealthOK()
+ */
+ public GroupRpcResponse isProxyHealthOK()
+ {
+ return this.invokeRpc("isProxyHealthOk");
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#markProxiesInError()
+ */
+ public GroupRpcResponse markProxiesInError()
+ {
+ return this.invokeRpc("markProxiesInError");
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#mcmpServerDiscoveryEvent(org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent)
+ */
+ public GroupRpcResponse mcmpServerDiscoveryEvent(MCMPServerDiscoveryEvent event)
+ {
+ try
+ {
+ return this.invokeRpc("mcmpServerDiscoveryEvent", new Object[] {
event }, DISC_EVENT_TYPES);
+ }
+ catch (Exception e)
+ {
+ return new ThrowableGroupRpcResponse(null, e);
+ }
+ }
+
+ /**
+ * @see org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#reset()
+ */
+ public GroupRpcResponse reset()
+ {
+ return this.invokeRpc("reset");
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequest(org.jboss.modcluster.mcmp.MCMPRequest)
+ */
+ public GroupRpcResponse sendRequest(MCMPRequest request)
+ {
+ return this.invokeRpc("sendRequest", new Object[] { request },
MCMPREQ_TYPES, true);
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequests(java.util.List)
+ */
+ public GroupRpcResponse sendRequests(List<MCMPRequest> requests)
+ {
+ return this.invokeRpc("sendRequests", new Object[] { requests },
MCMPREQS_TYPES, true);
+ }
+
+ private GroupRpcResponse invokeRpc(String methodName)
+ {
+ return this.invokeRpc(methodName, NULL_ARGS, NULL_TYPES, false);
+ }
+
+ private GroupRpcResponse invokeRpc(String methodName, Object[] args,
Class<?>[] types, boolean recordFailure)
+ {
+ try
+ {
+ return this.invokeRpc(methodName, args, types);
+ }
+ catch (Exception e)
+ {
+ if (recordFailure)
+ {
+ ClusteredMCMPHandlerImpl.this.recordRequestFailure();
+ }
+
+ throw Utils.convertToUnchecked(e);
+ }
+ }
+
+ private GroupRpcResponse invokeRpc(String methodName, Object[] args,
Class<?>[] types) throws Exception
+ {
+ List<?> responses =
ClusteredMCMPHandlerImpl.this.serviceKeyProvider.getHAPartition().callMethodOnCluster(ClusteredMCMPHandlerImpl.this.serviceKeyProvider.getHAServiceKey(),
methodName, args, types, false, new GroupRpcResponseFilter());
+
+ Throwable thrown = null;
+
+ for (Object obj : responses)
+ {
+ if (obj instanceof GroupRpcResponse)
+ {
+ return (GroupRpcResponse) obj;
+ }
+ else if (obj instanceof Throwable)
+ {
+ if (thrown == null)
+ {
+ thrown = (Throwable) obj;
+ }
+ }
+ else
+ {
+
log.warn(ClusteredMCMPHandlerImpl.this.sm.getString("modcluster.error.rpc.unexpected",
obj, methodName));
+ }
+ }
+
+ if (thrown != null)
+ {
+ throw Utils.convertToUnchecked(thrown);
+ }
+
+ throw new
IllegalStateException(ClusteredMCMPHandlerImpl.this.sm.getString("modcluster.error.rpc.noresp",
methodName));
+ }
+ }
+
+ private enum State
+ {
+ OK(false), REQUIRES_RESET(true), RESET_PENDING(true);
+
+ private boolean error;
+
+ State(boolean error)
+ {
+ this.error = error;
+ }
+
+ public boolean isError()
+ {
+ return this.error;
+ }
+
+ public State error()
+ {
+ return REQUIRES_RESET;
+ }
+
+ public State resetStart()
+ {
+ return this == REQUIRES_RESET ? RESET_PENDING : this;
+ }
+
+ public State resetEnd()
+ {
+ return this == RESET_PENDING ? OK : this;
+ }
+ }
+}
\ No newline at end of file
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/HASingletonAwareResetRequestSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/HASingletonAwareResetRequestSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/HASingletonAwareResetRequestSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,167 @@
+/*
+ * 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.modcluster.ha;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.catalina.Server;
+import org.apache.catalina.util.StringManager;
+import org.jboss.ha.framework.interfaces.HAServiceKeyProvider;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.config.BalancerConfiguration;
+import org.jboss.modcluster.config.NodeConfiguration;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPUtils;
+import org.jboss.modcluster.mcmp.ResetRequestSource;
+import org.jboss.modcluster.Constants;
+import org.jboss.modcluster.Utils;
+import org.jboss.modcluster.ha.rpc.ResetRequestGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.ResetRequestSourceRpcHandler;
+import org.jboss.modcluster.ha.rpc.ThrowableGroupRpcResponse;
+
+/**
+ * {@link ResetRequestSource} that provides different reset requests
+ * depending on whether or not it believes it is running on the singleton
+ * master.
+ *
+ * @author Brian Stansberry
+ */
+public class HASingletonAwareResetRequestSource implements ResetRequestSource
+{
+ static final String METHOD_NAME = "getResetRequests";
+ static final Object[] ARGS = new Object[0];
+ static final Class<?>[] TYPES = new Class[0];
+
+ private static final Logger log =
Logger.getLogger(HASingletonAwareResetRequestSource.class);
+
+ /**
+ * The string manager for this package.
+ */
+ private final StringManager sm = StringManager.getManager(Constants.Package);
+
+ private final NodeConfiguration nodeConfig;
+ private final BalancerConfiguration balancerConfig;
+ private final ResetRequestSourceRpcHandler<List<?>> rpcStub;
+ private volatile boolean master;
+ private volatile Server jbossWebServer;
+
+ public HASingletonAwareResetRequestSource(NodeConfiguration nodeConfig,
BalancerConfiguration balancerConfig, HAServiceKeyProvider serviceKeyProvider)
+ {
+ this.nodeConfig = nodeConfig;
+ this.balancerConfig = balancerConfig;
+ this.rpcStub = new RpcStub(serviceKeyProvider);
+ }
+
+ public List<MCMPRequest> getResetRequests()
+ {
+ if (this.master)
+ {
+ List<MCMPRequest> resets = this.getLocalResetRequests();
+ this.addRemoteRequests(resets);
+ return resets;
+ }
+
+ return Collections.emptyList();
+ }
+
+ public List<MCMPRequest> getLocalResetRequests()
+ {
+ if (this.jbossWebServer == null)
+ {
+ return new ArrayList<MCMPRequest>();
+ }
+
+ return MCMPUtils.getResetRequests(this.jbossWebServer, this.nodeConfig,
this.balancerConfig);
+ }
+
+ public boolean isMasterNode()
+ {
+ return this.master;
+ }
+
+ public void setMasterNode(boolean master)
+ {
+ this.master = master;
+ }
+
+ public void setJbossWebServer(Server jbossWebServer)
+ {
+ this.jbossWebServer = jbossWebServer;
+ }
+
+ private void addRemoteRequests(List<MCMPRequest> resets)
+ {
+ List<?> responses = this.rpcStub.getResetRequests();
+
+ for (Object response : responses)
+ {
+ if (response instanceof ResetRequestGroupRpcResponse)
+ {
+ resets.addAll(((ResetRequestGroupRpcResponse) response).getValue());
+ }
+ else if (response instanceof ThrowableGroupRpcResponse)
+ {
+ ThrowableGroupRpcResponse tgrr = (ThrowableGroupRpcResponse) response;
+ //FIXME what to do?
+ log.warn(this.sm.getString("modcluster.error.rpc.known",
METHOD_NAME, tgrr.getSender()), tgrr.getValue());
+ }
+ else if (response instanceof Throwable)
+ {
+ log.warn(this.sm.getString("modcluster.error.rpc.unknown",
METHOD_NAME), (Throwable) response);
+ }
+ else
+ {
+ log.error(this.sm.getString("modcluster.error.rpc.unexpected",
response, METHOD_NAME));
+ }
+
+ }
+ }
+
+ private class RpcStub implements ResetRequestSourceRpcHandler<List<?>>
+ {
+ private final HAServiceKeyProvider serviceKeyProvider;
+
+ public RpcStub(HAServiceKeyProvider serviceKeyProvider)
+ {
+ this.serviceKeyProvider = serviceKeyProvider;
+ }
+
+ /**
+ * @see
org.jboss.modcluster.ha.rpc.ResetRequestSourceRpcHandler#getResetRequests()
+ */
+ public List<?> getResetRequests()
+ {
+ try
+ {
+ return
this.serviceKeyProvider.getHAPartition().callMethodOnCluster(this.serviceKeyProvider.getHAServiceKey(),
METHOD_NAME, ARGS, TYPES, true);
+ }
+ catch (Exception e)
+ {
+ //FIXME what to do?
+ throw Utils.convertToUnchecked(e);
+ }
+ }
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ModClusterServiceDRMEntry.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ModClusterServiceDRMEntry.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/ModClusterServiceDRMEntry.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,182 @@
+/*
+ * 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.modcluster.ha;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+
+/**
+ * Represents the status of a given MCMP client's ability to communicate
+ * with MCMP servers.
+ *
+ * @author Brian Stansberry
+ */
+public class ModClusterServiceDRMEntry implements Serializable,
Comparable<ModClusterServiceDRMEntry>
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8275232749243297786L;
+
+ private final ClusterNode peer;
+ private final Set<MCMPServerState> mcmpServerStates;
+ private final Integer healthyEstablishedCount;
+ private final Integer establishedCount;
+ private final Integer healthyCount;
+ private final Integer knownCount;
+ private final Set<String> jvmRoutes = new HashSet<String>();
+
+ public ModClusterServiceDRMEntry(ClusterNode peer, Set<MCMPServerState>
mcmpServerStates)
+ {
+ assert peer != null : "peer is null";
+
+ this.peer = peer;
+ this.mcmpServerStates = mcmpServerStates;
+
+ int healthyEstablished = 0;
+ int knownEstablished = 0;
+ int healthy = 0;
+ int known = 0;
+
+ if (this.mcmpServerStates != null)
+ {
+ for (MCMPServerState state : this.mcmpServerStates)
+ {
+ known++;
+ if (state.getState() == MCMPServerState.State.OK)
+ {
+ healthy++;
+ if (state.isEstablished())
+ {
+ knownEstablished++;
+ healthyEstablished++;
+ }
+ }
+ else if (state.isEstablished())
+ {
+ knownEstablished++;
+ }
+ }
+ }
+
+ this.establishedCount = new Integer(knownEstablished);
+ this.healthyCount = new Integer(healthy);
+ this.healthyEstablishedCount = new Integer(healthyEstablished);
+ this.knownCount = new Integer(known);
+ }
+
+ public ClusterNode getPeer()
+ {
+ return this.peer;
+ }
+
+ public Set<MCMPServerState> getMCMPServerStates()
+ {
+ return this.mcmpServerStates;
+ }
+
+ public Set<String> getJvmRoutes()
+ {
+ synchronized (this.jvmRoutes)
+ {
+ return new HashSet<String>(this.jvmRoutes);
+ }
+ }
+
+ public void addJvmRoute(String jvmRoute)
+ {
+ synchronized (this.jvmRoutes)
+ {
+ this.jvmRoutes.add(jvmRoute);
+ }
+ }
+
+ public void removeJvmRoute(String jvmRoute)
+ {
+ synchronized (this.jvmRoutes)
+ {
+ this.jvmRoutes.remove(jvmRoute);
+ }
+ }
+
+ public int compareTo(ModClusterServiceDRMEntry other)
+ {
+ int result =
other.healthyEstablishedCount.compareTo(this.healthyEstablishedCount);
+ if (result == 0)
+ {
+ result = other.establishedCount.compareTo(this.establishedCount);
+ if (result == 0)
+ {
+ result = other.healthyCount.compareTo(this.healthyCount);
+ if (result == 0)
+ {
+ result = other.knownCount.compareTo(this.knownCount);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+
+ if (obj instanceof ModClusterServiceDRMEntry)
+ {
+ ModClusterServiceDRMEntry other = (ModClusterServiceDRMEntry) obj;
+ return (this.peer.equals(other.peer)
+ && this.safeEquals(this.mcmpServerStates,
other.mcmpServerStates)
+ && this.safeEquals(this.jvmRoutes, other.jvmRoutes));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = 17;
+ result += 23 * this.peer.hashCode();
+ result += 23 * (this.mcmpServerStates == null ? 0 :
this.mcmpServerStates.hashCode());
+ result += 23 * (this.jvmRoutes == null ? 0 : this.jvmRoutes.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString()
+ {
+ return new StringBuilder(this.getClass().getName())
+
.append("{peer=").append(this.peer).append("}").toString();
+ }
+
+ private boolean safeEquals(Object a, Object b)
+ {
+ return (a == b || (a != null && a.equals(b)));
+ }
+}
\ No newline at end of file
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/BooleanGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/BooleanGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/BooleanGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,50 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+
+/**
+ * A {@link GroupRpcResponse} that wraps a boolean return value.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class BooleanGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8932443264578153750L;
+
+ private final boolean value;
+
+ public BooleanGroupRpcResponse(ClusterNode sender, boolean value)
+ {
+ super(sender);
+ this.value = value;
+ }
+
+ public boolean getValue()
+ {
+ return this.value;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,47 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.util.List;
+
+import org.jboss.modcluster.mcmp.MCMPRequest;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface ClusteredMCMPHandlerRpcHandler
+{
+ GroupRpcResponse sendRequest(MCMPRequest request);
+
+ GroupRpcResponse sendRequests(List<MCMPRequest> requests);
+
+ GroupRpcResponse mcmpServerDiscoveryEvent(MCMPServerDiscoveryEvent event);
+
+ GroupRpcResponse getProxyConfiguration();
+
+ GroupRpcResponse isProxyHealthOK();
+
+ GroupRpcResponse markProxiesInError();
+
+ GroupRpcResponse reset();
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponse.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,52 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.io.Serializable;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.modcluster.ModClusterService;
+
+/**
+ * A response to a group RPC call made by {@link ModClusterService}.
+ *
+ * @author Brian Stansberry
+ */
+public class GroupRpcResponse implements Serializable
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 7427355308214918459L;
+
+ private final ClusterNode sender;
+
+ public GroupRpcResponse(ClusterNode sender)
+ {
+ this.sender = sender;
+ }
+
+ public ClusterNode getSender()
+ {
+ return this.sender;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponseFilter.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponseFilter.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/GroupRpcResponseFilter.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,53 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.interfaces.ResponseFilter;
+
+/**
+ * A {@link ResponseFilter} that accepts any GroupRpcResponse and doesn't
+ * need any further responses after receiving the first.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class GroupRpcResponseFilter implements ResponseFilter
+{
+ private boolean stillNeed = true;
+
+ public boolean isAcceptable(Object response, ClusterNode responder)
+ {
+ boolean acceptable = (response instanceof GroupRpcResponse);
+ if (acceptable)
+ this.stillNeed = false;
+
+ return acceptable;
+ }
+
+ public boolean needMoreResponses()
+ {
+ return this.stillNeed;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/InetAddressGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/InetAddressGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/InetAddressGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,53 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.net.InetAddress;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+
+/**
+ * A {@link GroupRpcResponse} that wraps an InetAddress return value.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class InetAddressGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8932443264578153750L;
+
+ private final InetAddress value;
+
+ public InetAddressGroupRpcResponse(ClusterNode sender, InetAddress value)
+ {
+ super(sender);
+ this.value = value;
+ }
+
+ public InetAddress getValue()
+ {
+ return this.value;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/IntegerGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/IntegerGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/IntegerGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,51 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+
+/**
+ * A {@link GroupRpcResponse} that wraps an int return value.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class IntegerGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8932443264578153750L;
+
+ private final int value;
+
+ public IntegerGroupRpcResponse(ClusterNode sender, int value)
+ {
+ super(sender);
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return this.value;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/MCMPServerDiscoveryEvent.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/MCMPServerDiscoveryEvent.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/MCMPServerDiscoveryEvent.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,94 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.io.Serializable;
+
+import net.jcip.annotations.Immutable;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.modcluster.mcmp.AddressPort;
+
+/**
+ * Event object indicating the discovery or requested removal of an
+ * {@link MCMPServer}.
+ *
+ * @author Brian Stansberry
+ */
+@Immutable
+public class MCMPServerDiscoveryEvent implements Serializable
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = -4615651826967237065L;
+
+ private final ClusterNode sender;
+ private final AddressPort mcmpServer;
+ private final boolean addition;
+ private final int eventIndex;
+
+ public MCMPServerDiscoveryEvent(ClusterNode sender, AddressPort mcmpServer, boolean
addition, int eventIndex)
+ {
+ assert sender != null : "sender is null";
+ assert mcmpServer != null : "mcmpServer is null";
+
+ this.sender = sender;
+ this.mcmpServer = mcmpServer;
+ this.addition = addition;
+ this.eventIndex = eventIndex;
+ }
+
+ /**
+ * Creates a new MCMPServerDiscoveryEvent with the same values as an existing
+ * one, but a new event index. Used in resending events.
+ *
+ * @param toRecreate
+ * @param newEventIndex
+ */
+ public MCMPServerDiscoveryEvent(MCMPServerDiscoveryEvent toRecreate, int
newEventIndex)
+ {
+ this(toRecreate.getSender(), toRecreate.getMCMPServer(), toRecreate.isAddition(),
newEventIndex);
+ }
+
+
+ public ClusterNode getSender()
+ {
+ return this.sender;
+ }
+
+ public AddressPort getMCMPServer()
+ {
+ return this.mcmpServer;
+ }
+
+ public boolean isAddition()
+ {
+ return this.addition;
+ }
+
+ public int getEventIndex()
+ {
+ return this.eventIndex;
+ }
+
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceRpcHandler.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceRpcHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceRpcHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,41 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.server.HAServiceEvent;
+import org.jboss.ha.framework.server.HAServiceRpcHandler;
+import org.jboss.modcluster.mcmp.MCMPServer;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface ModClusterServiceRpcHandler<T, S extends MCMPServer> extends
HAServiceRpcHandler<HAServiceEvent>
+{
+ void clusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses);
+
+ T getClusterCoordinatorState(Set<S> masterList);
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceStateGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceStateGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ModClusterServiceStateGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,81 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.util.List;
+import java.util.Set;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+
+/**
+ * GroupRpcResponse that provides the overall status picture for a
+ * ModClusterService instance.
+ *
+ * @author Brian Stansberry
+ */
+public class ModClusterServiceStateGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = -6591593007825931165L;
+
+ private final Set<MCMPServerState> states;
+ private final List<MCMPServerDiscoveryEvent> unacknowledgedEvents;
+ private final List<MCMPRequest> resetRequests;
+ private final int loadBalanceFactor;
+
+ public ModClusterServiceStateGroupRpcResponse(ClusterNode sender,
+ int loadBalanceFactor,
+ Set<MCMPServerState> states,
+ List<MCMPServerDiscoveryEvent> unacknowledgedEvents,
+ List<MCMPRequest> resetRequests)
+ {
+ super(sender);
+ this.loadBalanceFactor = loadBalanceFactor;
+ this.states = states;
+ this.unacknowledgedEvents = unacknowledgedEvents;
+ this.resetRequests = resetRequests;
+ }
+
+ public Set<MCMPServerState> getStates()
+ {
+ return this.states;
+ }
+
+ public List<MCMPServerDiscoveryEvent> getUnacknowledgedEvents()
+ {
+ return this.unacknowledgedEvents;
+ }
+
+ public List<MCMPRequest> getResetRequests()
+ {
+ return this.resetRequests;
+ }
+
+ public int getLoadBalanceFactor()
+ {
+ return this.loadBalanceFactor;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,66 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.util.Set;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+import org.jboss.modcluster.ha.ModClusterServiceDRMEntry;
+
+/**
+ * Extends {@link ModClusterServiceDRMEntry} to include information on
+ * the most recent discovery event from the peer that the current
+ * singleton master has included in the group-wide set of MCMP configurations.
+ *
+ * @author Brian Stansberry
+ */
+public class PeerMCMPDiscoveryStatus extends ModClusterServiceDRMEntry
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 3497115763128334162L;
+
+ private final MCMPServerDiscoveryEvent latestDiscoveryEvent;
+
+ /**
+ * Create a new PeerMCMPCommStatus.
+ *
+ * @param peer the id of the peer
+ * @param mcmpServerStates unmodifiable Set of MCMPServerState objects, or
+ * <code>null</code> if such a set of states
could
+ * not be obtained for the peer.
+ * @param latestDiscoveryEvent most recent discovery event received from the peer
+ */
+ public PeerMCMPDiscoveryStatus(ClusterNode peer, Set<MCMPServerState>
mcmpServerStates,
+ MCMPServerDiscoveryEvent latestDiscoveryEvent)
+ {
+ super(peer, mcmpServerStates);
+ this.latestDiscoveryEvent = latestDiscoveryEvent;
+ }
+
+ public MCMPServerDiscoveryEvent getLatestDiscoveryEvent()
+ {
+ return this.latestDiscoveryEvent;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,54 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import java.util.List;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+
+/**
+ * A {@link GroupRpcResponse} that wraps a List<MCMPRequest> return value.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class ResetRequestGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8932443264578153750L;
+
+ private final List<MCMPRequest> value;
+
+ public ResetRequestGroupRpcResponse(ClusterNode sender, List<MCMPRequest>
value)
+ {
+ super(sender);
+ this.value = value;
+ }
+
+ public List<MCMPRequest> getValue()
+ {
+ return this.value;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,32 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface ResetRequestSourceRpcHandler<T>
+{
+ T getResetRequests();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/StringGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/StringGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/StringGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,51 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+
+/**
+ * A {@link GroupRpcResponse} that wraps a String return value.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class StringGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8932443264578153750L;
+
+ private final String value;
+
+ public StringGroupRpcResponse(ClusterNode sender, String value)
+ {
+ super(sender);
+ this.value = value;
+ }
+
+ public String getValue()
+ {
+ return this.value;
+ }
+
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ThrowableGroupRpcResponse.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ThrowableGroupRpcResponse.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/ha/rpc/ThrowableGroupRpcResponse.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,60 @@
+/*
+ * 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.modcluster.ha.rpc;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+
+/**
+ * A {@link GroupRpcResponse} that wraps a String return value.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class ThrowableGroupRpcResponse extends GroupRpcResponse
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 8932443264578153750L;
+
+ private final Throwable value;
+
+ public ThrowableGroupRpcResponse(ClusterNode sender, Throwable value)
+ {
+ super(sender);
+ this.value = value;
+ }
+
+ public Throwable getValue()
+ {
+ return this.value;
+ }
+
+ public RuntimeException getValueAsRuntimeException()
+ {
+ if (this.value instanceof RuntimeException)
+ {
+ return (RuntimeException) this.value;
+ }
+
+ return new RuntimeException("Group RPC returned exception", this.value);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/LoadBalanceFactorProvider.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/LoadBalanceFactorProvider.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/LoadBalanceFactorProvider.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.load;
+
+/**
+ * Provides the load balance factor for a node.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public interface LoadBalanceFactorProvider
+{
+ int getLoadBalanceFactor();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProvider.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProvider.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProvider.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,215 @@
+/*
+ * 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.modcluster.load.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.catalina.util.StringManager;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.load.LoadBalanceFactorProvider;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.Constants;
+
+/**
+ * {@link LoadBalanceFactorProvider} implementation that periodically aggregates load
from a set of {@link LoadMetricSource}s.
+ *
+ * @author Paul Ferraro
+ */
+public class DynamicLoadBalanceFactorProvider implements LoadBalanceFactorProvider,
LoadMetricSourceRegistration, DynamicLoadBalanceFactorProviderMBean
+{
+ private final Logger log = Logger.getLogger(this.getClass());
+ private final StringManager sm = StringManager.getManager(Constants.Package);
+
+ private final Collection<LoadMetricSource> sources = new
ArrayList<LoadMetricSource>();
+ private final Map<LoadMetric, List<Double>> loadHistory = new
HashMap<LoadMetric, List<Double>>();
+
+ private volatile int decayFactor = 2;
+ private volatile int history = 10;
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.load.metric.MetricRegistration#register(org.jboss.modcluster.load.metric.LoadMetricSource)
+ */
+ public void add(LoadMetricSource source)
+ {
+ this.sources.add(source);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.LoadBalanceFactorProvider#getLoadBalanceFactor()
+ */
+ public synchronized int getLoadBalanceFactor()
+ {
+ int totalWeight = 0;
+ double totalWeightedLoad = 0;
+
+ for (LoadMetricSource source: this.sources)
+ {
+ Collection<? extends LoadMetric> metrics = source.getMetrics();
+
+ List<LoadMetric> metricList = new
ArrayList<LoadMetric>(metrics.size());
+
+ // Prune 0 weights since they will not contribute anything
+ for (LoadMetric metric: metrics)
+ {
+ if (metric.getWeight() != 0)
+ {
+ metricList.add(metric);
+ }
+ }
+
+ if (!metricList.isEmpty())
+ {
+ source.prepare();
+
+ try
+ {
+ for (LoadMetric metric: metricList)
+ {
+ try
+ {
+ // Normalize load with respect to capacity
+ List<Double> queue = this.recordLoad(metric, metric.getLoad()
/ metric.getCapacity());
+
+ int weight = metric.getWeight();
+
+ totalWeight += weight;
+ totalWeightedLoad += this.average(queue) * weight;
+ }
+ catch (Exception e)
+ {
+ this.log.error(e.getMessage(), e);
+ }
+ }
+ }
+ finally
+ {
+ source.cleanup();
+ }
+ }
+ }
+
+ // Convert load ratio to integer percentage and invert to express as "load
factor"
+ return 100 - (int) Math.round(100 * totalWeightedLoad / totalWeight);
+ }
+
+ private List<Double> recordLoad(LoadMetric metric, double load)
+ {
+ List<Double> queue = this.loadHistory.get(metric);
+
+ if (queue == null)
+ {
+ queue = new ArrayList<Double>(this.history);
+
+ this.loadHistory.put(metric, queue);
+ }
+ else
+ {
+ for (int i = queue.size(); i >= this.history; --i)
+ {
+ queue.remove(i - 1);
+ }
+ }
+
+ queue.add(0, new Double(load));
+
+ return queue;
+ }
+
+ /**
+ * Compute historical average using time decay function
+ * @param queue
+ * @return
+ */
+ private double average(List<Double> queue)
+ {
+ assert !queue.isEmpty();
+
+ double totalLoad = 0;
+ double totalDecay = 0;
+ double decayFactor = this.decayFactor;
+
+ // Historical value contribute an exponentially decayed factor
+ for (int i = 0; i < queue.size(); ++i)
+ {
+ double decay = 1 / Math.pow(decayFactor, i);
+
+ totalDecay += decay;
+ totalLoad += queue.get(i).doubleValue() * decay;
+ }
+
+ return totalLoad / totalDecay;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.load.impl.DynamicLoadBalanceFactorProviderMBean#getDecayFactor()
+ */
+ public int getDecayFactor()
+ {
+ return this.decayFactor;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.load.impl.DynamicLoadBalanceFactorProviderMBean#setDecayFactor(int)
+ */
+ public void setDecayFactor(int decayFactor)
+ {
+ if (decayFactor <= 0)
+ {
+ throw new
IllegalArgumentException(this.sm.getString("modcluster.error.nonPositiveAttribute",
"decayFactor", String.valueOf(decayFactor)));
+ }
+
+ this.decayFactor = decayFactor;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.load.impl.DynamicLoadBalanceFactorProviderMBean#getHistory()
+ */
+ public int getHistory()
+ {
+ return this.history;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see
org.jboss.modcluster.load.impl.DynamicLoadBalanceFactorProviderMBean#setHistory(int)
+ */
+ public void setHistory(int history)
+ {
+ if (history <= 0)
+ {
+ throw new
IllegalArgumentException(this.sm.getString("modcluster.error.nonPositiveAttribute",
"history", String.valueOf(history)));
+ }
+
+ this.history = history;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProviderMBean.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProviderMBean.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/DynamicLoadBalanceFactorProviderMBean.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,55 @@
+/*
+ * 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.modcluster.load.impl;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface DynamicLoadBalanceFactorProviderMBean
+{
+ /**
+ * Returns the history count.
+ * @return a positive integer
+ */
+ int getHistory();
+
+ /**
+ * Sets the number of historical load values to consider when calculating the load
balance factor.
+ * @param history
+ * @throws IllegalArgumentException if specified value is not a positive number
+ */
+ void setHistory(int history);
+
+ /**
+ * Returns the exponential decay factor.
+ * @return a positive integer
+ */
+ int getDecayFactor();
+
+ /**
+ * Sets the exponential decay factor to be applied to historical load values.
+ * @param decayFactor the new decay factor
+ * @throws IllegalArgumentException if specified value is not a positive number
+ */
+ void setDecayFactor(int decayFactor);
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/StaticLoadBalanceFactorProvider.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/StaticLoadBalanceFactorProvider.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/impl/StaticLoadBalanceFactorProvider.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,51 @@
+/*
+ * 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.modcluster.load.impl;
+
+import org.jboss.modcluster.load.LoadBalanceFactorProvider;
+
+/**
+ * A {@link LoadManagerImpl} that returns a static value.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public class StaticLoadBalanceFactorProvider implements LoadBalanceFactorProvider
+{
+ private int loadBalanceFactor = 1;
+
+ // ------------------------------------------------------------- LoadManager
+
+ public int getLoadBalanceFactor()
+ {
+ return this.loadBalanceFactor;
+ }
+
+ // -------------------------------------------------------------- Properties
+
+ public void setLoadBalanceFactor(int loadBalanceFactor)
+ {
+ this.loadBalanceFactor = loadBalanceFactor;
+ }
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetric.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,50 @@
+/*
+ * 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.modcluster.load.metric;
+
+/**
+ * Represents a specific load metric.
+ * @author Paul Ferraro
+ */
+public interface LoadMetric
+{
+ /**
+ * Returns the "weight" of this metric, i.e. significance of this load
metric compared to the other metrics.
+ * @return the weight of the metric
+ */
+ int getWeight();
+
+ /**
+ * Returns the load capacity of this metric.
+ * Used to normalize the value returned by {@link #getLoad()} expressed as a
percentage of the capacity, such that:
+ * 0 <= ({@link #getLoad()} / {@link #getCapacity()}) < 1
+ * @return the estimated capacity of this metric.
+ */
+ double getCapacity();
+
+ /**
+ * Returns the current load. This value only has meaning when expressed as a ratio of
the capacity.
+ * @return the current load.
+ * @throws Exception if there was an error fetching this metric.
+ */
+ double getLoad() throws Exception;
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricMBean.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricMBean.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricMBean.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,34 @@
+/*
+ * 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.modcluster.load.metric;
+
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface LoadMetricMBean extends LoadMetric
+{
+ void setWeight(int weight);
+
+ void setCapacity(double capacity);
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,47 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Collection;
+
+/**
+ * A source for obtaining load metrics.
+ * @author Paul Ferraro
+ */
+public interface LoadMetricSource
+{
+ /**
+ * Returns the collection of metrics registered with this source.
+ * @return the metrics from this source
+ */
+ Collection<LoadMetric> getMetrics();
+
+ /**
+ * Prepare any resource required to collect load metrics
+ */
+ void prepare();
+
+ /**
+ * Cleanup any resources used to collect load metrics
+ */
+ void cleanup();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSourceRegistration.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSourceRegistration.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/LoadMetricSourceRegistration.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,32 @@
+/*
+ * 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.modcluster.load.metric;
+
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface LoadMetricSourceRegistration
+{
+ void add(LoadMetricSource source);
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,77 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricMBean;
+
+/**
+ * Abstract {@link LoadMetric} implementation with basic mutators/accessors.
+ *
+ * @author Paul Ferraro
+ */
+public abstract class AbstractLoadMetric implements LoadMetricMBean
+{
+ private volatile int weight = 0;
+ private volatile double capacity = 1;
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getWeight()
+ */
+ public int getWeight()
+ {
+ return this.weight;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricMBean#setWeight(int)
+ */
+ public void setWeight(int weight)
+ {
+ this.weight = weight;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getCapacity()
+ */
+ public double getCapacity()
+ {
+ return this.capacity;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricMBean#setCapacity(double)
+ */
+ public void setCapacity(double capacity)
+ {
+ if (capacity <= 0)
+ {
+ throw new IllegalArgumentException("Capacity be greater than zero.");
+ }
+
+ this.capacity = capacity;
+ }
+}
\ No newline at end of file
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AbstractLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,76 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * Abstract {@link LoadMetricSource} that allows a {@link LoadMetric} to register with
it.
+ *
+ * @author Paul Ferraro
+ */
+public abstract class AbstractLoadMetricSource implements LoadMetricSource
+{
+ private Collection<LoadMetric> metrics = new LinkedList<LoadMetric>();
+
+ protected AbstractLoadMetricSource(LoadMetricSourceRegistration registration)
+ {
+ registration.add(this);
+ }
+
+ public void add(LoadMetric metric)
+ {
+ this.metrics.add(metric);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricSource#getMetrics()
+ */
+ public Collection<LoadMetric> getMetrics()
+ {
+ return this.metrics;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricSource#prepare()
+ */
+ public void prepare()
+ {
+ // Nothing to open
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricSource#cleanup()
+ */
+ public void cleanup()
+ {
+ // Nothing to close
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ActiveSessionsLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ActiveSessionsLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ActiveSessionsLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,44 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * {@link LoadMetric} implementation that returns the total number of active web
sessions.
+ *
+ * @author Paul Ferraro
+ */
+public class ActiveSessionsLoadMetric extends MBeanAttributeLoadMetric
+{
+ private static final String DEFAULT_ATTRIBUTE = "LocalActiveSessions";
+
+ public ActiveSessionsLoadMetric(SessionLoadMetricSource source)
+ {
+ this(source, DEFAULT_ATTRIBUTE);
+ }
+
+ public ActiveSessionsLoadMetric(SessionLoadMetricSource source, String attribute)
+ {
+ super(source, attribute);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AverageSystemLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AverageSystemLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/AverageSystemLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,71 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.lang.management.OperatingSystemMXBean;
+
+import javax.management.JMException;
+
+import org.jboss.logging.Logger;
+
+/**
+ * Uses {@link OperatingSystemMXBean#getSystemLoadAverage} to calculate average system
load.
+ * Only supported on Java 1.6 or later.
+ *
+ * @author Paul Ferraro
+ */
+public class AverageSystemLoadMetric extends AbstractLoadMetric
+{
+ private static final String SYSTEM_LOAD_AVERAGE = "SystemLoadAverage";
+
+ private final OperatingSystemLoadMetricSource source;
+ private final Logger log = Logger.getLogger(this.getClass());
+
+ /**
+ * Create a new SystemLoadMetric.
+ *
+ * @param registration
+ */
+ public AverageSystemLoadMetric(OperatingSystemLoadMetricSource source)
+ {
+ this.source = source;
+
+ if (this.source.exists(SYSTEM_LOAD_AVERAGE))
+ {
+ this.source.add(this);
+ }
+ else
+ {
+ this.log.warn(this.getClass().getName() + " discarded. This metric
requires the "
+ + SYSTEM_LOAD_AVERAGE + " OperatingSystemMXBean attribute found in
Java 1.6 or later.");
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getLoad()
+ */
+ public double getLoad() throws JMException
+ {
+ return this.source.getAttribute(SYSTEM_LOAD_AVERAGE, Double.class).doubleValue();
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/BusyConnectorsLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/BusyConnectorsLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/BusyConnectorsLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,40 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * {@link LoadMetric} implementation that returns the total number of busy connector
threads.
+ *
+ * @author Paul Ferraro
+ */
+public class BusyConnectorsLoadMetric extends MBeanAttributeRatioLoadMetric
+{
+ private static final String CURRENT_THREADS_BUSY = "currentThreadsBusy";
+ private static final String MAX_THREADS = "maxThreads";
+
+ public BusyConnectorsLoadMetric(ThreadPoolLoadMetricSource source)
+ {
+ super(source, CURRENT_THREADS_BUSY, MAX_THREADS);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,84 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * {@link LoadMetricSource} implementation that simplifies generic mbean access to
+ * a set of JBoss JCA connection pools.
+ */
+public class ConnectionPoolLoadMetricSource extends MBeanQueryLoadMetricSource
+{
+ private static final String DEFAULT_PATTERN =
"jboss.jca:service=ManagedConnectionPool,*";
+
+ /**
+ * Create a new ConnectionPoolLoadMetricSource.
+ *
+ * @param registration
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public ConnectionPoolLoadMetricSource(LoadMetricSourceRegistration registration,
MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN, server);
+ }
+
+ /**
+ * Create a new ConnectionPoolLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public ConnectionPoolLoadMetricSource(LoadMetricSourceRegistration registration,
String pattern, MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, pattern, server);
+ }
+
+ /**
+ * Create a new ConnectionPoolLoadMetricSource.
+ *
+ * @param registration
+ * @throws MalformedObjectNameException
+ */
+ public ConnectionPoolLoadMetricSource(LoadMetricSourceRegistration registration)
throws MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN);
+ }
+
+ /**
+ * Create a new ConnectionPoolLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @throws MalformedObjectNameException
+ */
+ public ConnectionPoolLoadMetricSource(LoadMetricSourceRegistration registration,
String pattern) throws MalformedObjectNameException
+ {
+ super(registration, pattern);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolUsageLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolUsageLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ConnectionPoolUsageLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,45 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * {@link LoadMetric} implementation that returns the usage ratio of a connection pool.
+ *
+ * @author Paul Ferraro
+ */
+public class ConnectionPoolUsageLoadMetric extends MBeanAttributeRatioLoadMetric
+{
+ private static final String DEFAULT_USED_ATTRIBUTE =
"InUseConnectionCount";
+ private static final String DEFAULT_MAX_ATTRIBUTE = "MaxSize";
+
+ public ConnectionPoolUsageLoadMetric(ConnectionPoolLoadMetricSource source)
+ {
+ this(source, DEFAULT_USED_ATTRIBUTE, DEFAULT_MAX_ATTRIBUTE);
+ }
+
+ public ConnectionPoolUsageLoadMetric(ConnectionPoolLoadMetricSource source, String
usedAttribute, String maxAttribute)
+ {
+ super(source, usedAttribute, maxAttribute);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/DeterministicLoadState.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/DeterministicLoadState.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/DeterministicLoadState.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,48 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Computes incremental load change per second from record of previous load.
+ * @author Paul Ferraro
+ */
+public class DeterministicLoadState
+{
+ private final AtomicReference<Double> currentLoad = new
AtomicReference<Double>(new Double(0));
+ private final AtomicLong currentTime = new AtomicLong(System.currentTimeMillis());
+
+ public double delta(double currentLoad)
+ {
+ long currentTime = System.currentTimeMillis();
+ long previousTime = this.currentTime.getAndSet(currentTime);
+
+ double previousLoad = this.currentLoad.getAndSet(new
Double(currentLoad)).doubleValue();
+
+ double seconds = (currentTime - previousTime) / 1000d;
+
+ // Normalize by time interval (in seconds)
+ return (currentLoad - previousLoad) / seconds;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/HeapMemoryUsageLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/HeapMemoryUsageLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/HeapMemoryUsageLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,72 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+
+/**
+ * {@link LoadMetric} implementation that returns the heap memory usage ratio.
+ *
+ * @author Paul Ferraro
+ */
+public class HeapMemoryUsageLoadMetric extends SingleLoadMetricSource
+{
+ private final MemoryMXBean bean;
+
+ /**
+ * Create a new SystemLoadBalanceMetricProvider.
+ *
+ * @param registration
+ */
+ public HeapMemoryUsageLoadMetric(LoadMetricSourceRegistration registration)
+ {
+ this(registration, ManagementFactory.getMemoryMXBean());
+ }
+
+ /**
+ * Create a new SystemLoadBalanceMetricProvider.
+ *
+ * @param registration
+ */
+ public HeapMemoryUsageLoadMetric(LoadMetricSourceRegistration registration,
MemoryMXBean bean)
+ {
+ super(registration);
+
+ this.bean = bean;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getLoad()
+ */
+ public double getLoad()
+ {
+ MemoryUsage usage = this.bean.getHeapMemoryUsage();
+
+ return ((double) usage.getUsed()) / usage.getMax();
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,62 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.util.List;
+
+import javax.management.JMException;
+
+/**
+ * Generic {@link LoadMetric} whose load is the aggregated value of an mbean attribute.
+ * @author Paul Ferraro
+ */
+public class MBeanAttributeLoadMetric extends AbstractLoadMetric
+{
+ private final MBeanQueryLoadMetricSource source;
+ private final String attribute;
+
+ protected MBeanAttributeLoadMetric(MBeanQueryLoadMetricSource source, String
attribute)
+ {
+ this.source = source;
+ this.attribute = attribute;
+
+ this.source.add(this);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getLoad()
+ */
+ public double getLoad() throws JMException
+ {
+ double load = 0;
+
+ List<Number> results = this.source.getAttributes(this.attribute,
Number.class);
+
+ for (Number result: results)
+ {
+ load += result.doubleValue();
+ }
+
+ return load;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeRatioLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeRatioLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanAttributeRatioLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,75 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.util.List;
+
+import javax.management.JMException;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * Generic {@link LoadMetric} whose load is the ratio of 2 aggregated mbean attributes.
+ * @author Paul Ferraro
+ */
+public class MBeanAttributeRatioLoadMetric extends AbstractLoadMetric
+{
+ private final MBeanQueryLoadMetricSource source;
+ private final String dividendAttribute;
+ private final String divisorAttribute;
+
+ protected MBeanAttributeRatioLoadMetric(MBeanQueryLoadMetricSource source, String
currentAttribute, String maxAttribute)
+ {
+ this.source = source;
+ this.dividendAttribute = currentAttribute;
+ this.divisorAttribute = maxAttribute;
+
+ this.source.add(this);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getLoad()
+ */
+ public double getLoad() throws JMException
+ {
+ double dividend = 0;
+
+ List<Number> results = this.source.getAttributes(this.dividendAttribute,
Number.class);
+
+ for (Number result: results)
+ {
+ dividend += result.doubleValue();
+ }
+
+ double divisor = 0;
+
+ results = this.source.getAttributes(this.divisorAttribute, Number.class);
+
+ for (Number result: results)
+ {
+ divisor += result.doubleValue();
+ }
+
+ return dividend / divisor;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanQueryLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanQueryLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/MBeanQueryLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,104 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * Abstract {@link LoadMetricSource} that queries the mbean server for the set of beans
to be made available to its registered {@link LoadMetric}s.
+ *
+ * @author Paul Ferraro
+ */
+public abstract class MBeanQueryLoadMetricSource extends AbstractLoadMetricSource
+{
+ private final MBeanServer server;
+ private final ObjectName pattern;
+
+ private transient Set<ObjectName> objectNames;
+
+ protected MBeanQueryLoadMetricSource(LoadMetricSourceRegistration registration, String
pattern) throws MalformedObjectNameException
+ {
+ this(registration, pattern, ManagementFactory.getPlatformMBeanServer());
+ }
+
+ protected MBeanQueryLoadMetricSource(LoadMetricSourceRegistration registration, String
pattern, MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration);
+
+ this.pattern = ObjectName.getInstance(pattern);
+ this.server = server;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.impl.AbstractLoadMetricSource#prepare()
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void prepare()
+ {
+ this.objectNames = this.pattern.isPattern() ? this.server.queryNames(this.pattern,
null) : Collections.singleton(this.pattern);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.impl.AbstractLoadMetricSource#cleanup()
+ */
+ @Override
+ public void cleanup()
+ {
+ this.objectNames = null;
+ }
+
+ /**
+ * Collects the attribute values for each mbean matching the object name pattern
+ * @param <T> the type of the attribute
+ * @param attribute the mbean attribute name
+ * @param targetClass the type of the attribute
+ * @return a list of attribute values for each mbean
+ * @throws JMException
+ */
+ public <T> List<T> getAttributes(String attribute, Class<T>
targetClass) throws JMException
+ {
+ List<T> list = new ArrayList<T>(this.objectNames.size());
+
+ for (ObjectName name: this.objectNames)
+ {
+ list.add(targetClass.cast(this.server.getAttribute(name, attribute)));
+ }
+
+ return list;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/OperatingSystemLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/OperatingSystemLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/OperatingSystemLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,126 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * Abstract {@link LoadMetricSource} implementation that simplifies generic access to the
{@link java.lang.management.OperatingSystemMXBean}.
+ *
+ * @author Paul Ferraro
+ */
+public class OperatingSystemLoadMetricSource extends AbstractLoadMetricSource
+{
+ private final MBeanServer server;
+ private final ObjectName name;
+
+ /**
+ * Create a new OperatingSystemLoadMetricSource.
+ *
+ * @param registration
+ */
+ public OperatingSystemLoadMetricSource(LoadMetricSourceRegistration registration)
+ {
+ this(registration, ManagementFactory.getPlatformMBeanServer());
+ }
+
+ /**
+ * Create a new OperatingSystemLoadMetricSource.
+ *
+ * @param registration
+ */
+ public OperatingSystemLoadMetricSource(LoadMetricSourceRegistration registration,
MBeanServer server)
+ {
+ super(registration);
+
+ this.server = server;
+
+ try
+ {
+ this.name =
ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+ }
+ catch (MalformedObjectNameException e)
+ {
+ // Should never happen for a platform mxbean
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Indicates whether or not all of the specified attributes exist on this mbean
+ *
+ * @param attributes any number of attributes
+ * @return true if all of the specified attributes exist, false otherwise
+ */
+ public boolean exists(String... attributes)
+ {
+ Set<String> missingAttributes = new TreeSet<String>();
+
+ for (String attribute: attributes)
+ {
+ missingAttributes.add(attribute);
+ }
+
+ try
+ {
+ MBeanInfo info = this.server.getMBeanInfo(this.name);
+
+ for (MBeanAttributeInfo attribute: info.getAttributes())
+ {
+ missingAttributes.remove(attribute.getName());
+ }
+
+ return missingAttributes.isEmpty();
+ }
+ catch (JMException e)
+ {
+ // Should never happen for a platform mxbean
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns the value of the specified attribute, casted to the specified type.
+ *
+ * @param <T> the type of the attribute
+ * @param attribute an attribute name
+ * @param targetClass the type of the attribute
+ * @return the attribute value
+ * @throws JMException
+ */
+ public <T> T getAttribute(String attribute, Class<T> targetClass) throws
JMException
+ {
+ return targetClass.cast(this.server.getAttribute(this.name, attribute));
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ReceiveTrafficLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ReceiveTrafficLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ReceiveTrafficLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,53 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.JMException;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * {@link LoadMetric} implementation that returns the incoming bandwidth in KB.
+ * @author Paul Ferraro
+ */
+public class ReceiveTrafficLoadMetric extends MBeanAttributeLoadMetric
+{
+ private static final String RECEIVE_COUNT = "bytesReceived";
+
+ private final DeterministicLoadState state = new DeterministicLoadState();
+
+ public ReceiveTrafficLoadMetric(RequestProcessorLoadMetricSource source)
+ {
+ super(source, RECEIVE_COUNT);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.impl.MBeanAttributeLoadMetric#getLoad()
+ */
+ @Override
+ public double getLoad() throws JMException
+ {
+ // Convert to KB/sec
+ return this.state.delta(super.getLoad() / 1000);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestCountLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestCountLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestCountLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,53 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.JMException;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * {@link LoadMetric} implementation that returns the number of web requests.
+ *
+ * @author Paul Ferraro
+ */
+public class RequestCountLoadMetric extends MBeanAttributeLoadMetric
+{
+ private static final String REQUEST_COUNT = "requestCount";
+
+ private final DeterministicLoadState state = new DeterministicLoadState();
+
+ public RequestCountLoadMetric(RequestProcessorLoadMetricSource source)
+ {
+ super(source, REQUEST_COUNT);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.impl.MBeanAttributeLoadMetric#getLoad()
+ */
+ @Override
+ public double getLoad() throws JMException
+ {
+ return this.state.delta(super.getLoad());
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestProcessorLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestProcessorLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/RequestProcessorLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,86 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * {@link LoadMetricSource} implementation that simplifies generic mbean access to
+ * the JBossWeb request processors.
+ *
+ * @author Paul Ferraro
+ */
+public class RequestProcessorLoadMetricSource extends MBeanQueryLoadMetricSource
+{
+ private static final String DEFAULT_PATTERN =
"jboss.web:type=GlobalRequestProcessor,*";
+
+ /**
+ * Create a new GlobalRequestProcessorLoadMetricSource.
+ *
+ * @param registration
+ * @throws MalformedObjectNameException
+ */
+ public RequestProcessorLoadMetricSource(LoadMetricSourceRegistration registration)
throws MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN);
+ }
+
+ /**
+ * Create a new GlobalRequestProcessorLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @throws MalformedObjectNameException
+ */
+ public RequestProcessorLoadMetricSource(LoadMetricSourceRegistration registration,
String pattern) throws MalformedObjectNameException
+ {
+ super(registration, pattern);
+ }
+
+ /**
+ * Create a new GlobalRequestProcessorLoadMetricSource.
+ *
+ * @param registration
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public RequestProcessorLoadMetricSource(LoadMetricSourceRegistration registration,
MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN, server);
+ }
+
+ /**
+ * Create a new GlobalRequestProcessorLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public RequestProcessorLoadMetricSource(LoadMetricSourceRegistration registration,
String pattern, MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, pattern, server);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SendTrafficLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SendTrafficLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SendTrafficLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,54 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.JMException;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+/**
+ * {@link LoadMetric} implementation that returns the outgoing bandwidth in KB.
+ *
+ * @author Paul Ferraro
+ */
+public class SendTrafficLoadMetric extends MBeanAttributeLoadMetric
+{
+ private static final String SEND_COUNT = "bytesSent";
+
+ private final DeterministicLoadState state = new DeterministicLoadState();
+
+ public SendTrafficLoadMetric(RequestProcessorLoadMetricSource source)
+ {
+ super(source, SEND_COUNT);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.impl.MBeanAttributeLoadMetric#getLoad()
+ */
+ @Override
+ public double getLoad() throws JMException
+ {
+ // Convert to KB/sec
+ return this.state.delta(super.getLoad() / 1000);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SessionLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SessionLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SessionLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,86 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * {@link LoadMetricSource} implementation that simplifies generic mbean access to
+ * all JBossWeb session managers.
+ *
+ * @author Paul Ferraro
+ */
+public class SessionLoadMetricSource extends MBeanQueryLoadMetricSource
+{
+ private static final String DEFAULT_PATTERN = "jboss.web:type=Manager,*";
+
+ /**
+ * Create a new SessionLoadMetricSource.
+ *
+ * @param registration
+ * @throws MalformedObjectNameException
+ */
+ public SessionLoadMetricSource(LoadMetricSourceRegistration registration) throws
MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN);
+ }
+
+ /**
+ * Create a new SessionLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @throws MalformedObjectNameException
+ */
+ public SessionLoadMetricSource(LoadMetricSourceRegistration registration, String
pattern) throws MalformedObjectNameException
+ {
+ super(registration, pattern);
+ }
+
+ /**
+ * Create a new SessionLoadMetricSource.
+ *
+ * @param registration
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public SessionLoadMetricSource(LoadMetricSourceRegistration registration, MBeanServer
server) throws MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN, server);
+ }
+
+ /**
+ * Create a new SessionLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public SessionLoadMetricSource(LoadMetricSourceRegistration registration, String
pattern, MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, pattern, server);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SingleLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SingleLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SingleLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,71 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+
+/**
+ * Abstract {@link LoadMetricSource} + {@link LoadMetric} implementation that returns a
single metric.
+ *
+ * @author Paul Ferraro
+ */
+public abstract class SingleLoadMetricSource extends AbstractLoadMetric implements
LoadMetricSource
+{
+ protected SingleLoadMetricSource(LoadMetricSourceRegistration registration)
+ {
+ registration.add(this);
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricSource#prepare()
+ */
+ public void prepare()
+ {
+ // Nothing to prepare
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricSource#cleanup()
+ */
+ public void cleanup()
+ {
+ // Nothing to cleanup
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetricSource#getMetrics()
+ */
+ public Collection<LoadMetric> getMetrics()
+ {
+ // Silly that we need to cast to prevent a compiler error, no?
+ return Collections.singleton((LoadMetric) this);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SystemMemoryUsageLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SystemMemoryUsageLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/SystemMemoryUsageLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,78 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.util.Arrays;
+
+import javax.management.JMException;
+
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.load.metric.LoadMetric;
+
+
+/**
+ * {@link LoadMetric} implementation that uses {@link
com.sun.management.OperatingSystemMXBean}
+ * to determine system memory usage.
+ *
+ * @author Paul Ferraro
+ */
+public class SystemMemoryUsageLoadMetric extends AbstractLoadMetric
+{
+ private static final String FREE_MEMORY = "FreePhysicalMemorySize";
+ private static final String TOTAL_MEMORY = "TotalPhysicalMemorySize";
+
+ private final OperatingSystemLoadMetricSource source;
+ private final Logger log = Logger.getLogger(this.getClass());
+
+ /**
+ * Create a new SystemMemoryUsageLoadMetric.
+ *
+ * @param registration
+ */
+ public SystemMemoryUsageLoadMetric(OperatingSystemLoadMetricSource source)
+ {
+ this.source = source;
+
+ if (this.source.exists(FREE_MEMORY, TOTAL_MEMORY))
+ {
+ this.source.add(this);
+ }
+ else
+ {
+ this.log.warn(this.getClass().getName() + " discarded."
+ + "This metric requires the following OperatingSystemMXBean
attributes: "
+ + Arrays.asList(FREE_MEMORY, TOTAL_MEMORY));
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getLoad()
+ */
+ public double getLoad() throws JMException
+ {
+ long free = this.source.getAttribute(FREE_MEMORY, Long.class).longValue();
+ long total = this.source.getAttribute(TOTAL_MEMORY, Long.class).longValue();
+
+ return ((double) free) / total;
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadCountLoadMetric.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadCountLoadMetric.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadCountLoadMetric.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,67 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class ThreadCountLoadMetric extends SingleLoadMetricSource
+{
+ private final ThreadMXBean bean;
+
+ /**
+ * Create a new ThreadCountLoadMetric.
+ *
+ * @param registration
+ */
+ public ThreadCountLoadMetric(LoadMetricSourceRegistration registration)
+ {
+ this(registration, ManagementFactory.getThreadMXBean());
+ }
+
+ /**
+ * Create a new ThreadCountLoadMetric.
+ *
+ * @param registration
+ */
+ public ThreadCountLoadMetric(LoadMetricSourceRegistration registration, ThreadMXBean
bean)
+ {
+ super(registration);
+
+ this.bean = bean;
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.load.metric.LoadMetric#getLoad()
+ */
+ public double getLoad()
+ {
+ return this.bean.getThreadCount();
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadPoolLoadMetricSource.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadPoolLoadMetricSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/load/metric/impl/ThreadPoolLoadMetricSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,86 @@
+/*
+ * 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.modcluster.load.metric.impl;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+
+/**
+ * {@link LoadMetricSource} implementation that simplifies generic mbean access to
+ * all JBossWeb connector thread pools.
+ *
+ * @author Paul Ferraro
+ */
+public class ThreadPoolLoadMetricSource extends MBeanQueryLoadMetricSource
+{
+ private static final String DEFAULT_PATTERN =
"jboss.web:type=ThreadPool,*";
+
+ /**
+ * Create a new ThreadPoolLoadMetricSource.
+ *
+ * @param registration
+ * @throws MalformedObjectNameException
+ */
+ public ThreadPoolLoadMetricSource(LoadMetricSourceRegistration registration) throws
MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN);
+ }
+
+ /**
+ * Create a new ThreadPoolLoadMetricSource.
+ *
+ * @param registration
+ * @param patterh
+ * @throws MalformedObjectNameException
+ */
+ public ThreadPoolLoadMetricSource(LoadMetricSourceRegistration registration, String
pattern) throws MalformedObjectNameException
+ {
+ super(registration, pattern);
+ }
+
+ /**
+ * Create a new ThreadPoolLoadMetricSource.
+ *
+ * @param registration
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public ThreadPoolLoadMetricSource(LoadMetricSourceRegistration registration,
MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, DEFAULT_PATTERN, server);
+ }
+
+ /**
+ * Create a new ThreadPoolLoadMetricSource.
+ *
+ * @param registration
+ * @param pattern
+ * @param server
+ * @throws MalformedObjectNameException
+ */
+ public ThreadPoolLoadMetricSource(LoadMetricSourceRegistration registration, String
pattern, MBeanServer server) throws MalformedObjectNameException
+ {
+ super(registration, pattern, server);
+ }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mbeans-descriptors.xml
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mbeans-descriptors.xml
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/mbeans-descriptors.xml 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,138 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+ <mbean name="ClusterListener"
+ description="Cluster listener for mod_cluster"
+ domain="Catalina"
+ group="Listener"
+ type="org.jboss.web.cluster.ClusterListener">
+
+ <attribute name="className"
+ description="Fully qualified class name of the managed object"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="containerName"
+ description="Object name of the container"
+ type="javax.management.ObjectName"/>
+
+ <attribute name="proxyConfiguration"
+ description="Get the mod_cluster configuration"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="proxyList"
+ description="Comma delimited list of proxy servers"
+ type="java.lang.String"/>
+
+ <attribute name="socketTimeout"
+ description="Connection timeout for communication with the
proxy"
+ type="int"/>
+
+ <attribute name="advertise"
+ description="Enable autodiscovery of httpd servers"
+ type="boolean"/>
+
+ <attribute name="advertiseGroupAddress"
+ description="Multicast address for discovery"
+ type="java.lang.String"/>
+
+ <attribute name="advertisePort"
+ description="Multicast port for discovery"
+ type="int"/>
+
+ <attribute name="advertiseSecurityKey"
+ description="Security key for discovery"
+ type="java.lang.String"/>
+
+ <attribute name="domain"
+ description="Domain parameter, which allows tying a jvmRoute to a
particular domain"
+ type="java.lang.String"/>
+
+ <attribute name="flushPackets"
+ description="Allows controlling flushing of packets"
+ type="boolean"/>
+
+ <attribute name="flushWait"
+ description="Time in ms to wait before flushing packets"
+ type="int"/>
+
+ <attribute name="ping"
+ description="Time in s to wait for a pong answer to a ping"
+ type="int"/>
+
+ <attribute name="smax"
+ description="Maximum time on seconds for idle connections above
smax"
+ type="int"/>
+
+ <attribute name="balancer"
+ description="Name of the balancer"
+ type="java.lang.String"/>
+
+ <attribute name="stickySession"
+ description="Enables sticky sessions"
+ type="boolean"/>
+
+ <attribute name="stickySessionRemove"
+ description="Remove session when the request cannot be routed to the
right node"
+ type="boolean"/>
+
+ <attribute name="stickySessionForce"
+ description="Return an error when the request cannot be routed to the
right node"
+ type="boolean"/>
+
+ <attribute name="workerTimeout"
+ description="Timeout to wait for an available worker (default is no
wait)"
+ type="int"/>
+
+ <attribute name="maxAttempts"
+ description="Maximum number of attempts to send the request to the
backend server"
+ type="int"/>
+
+ <operation name="refresh"
+ description="Refresh configuration"
+ impact="ACTION"
+ returnType="void"/>
+
+ <operation name="reset"
+ description="Move the node out of an error state"
+ impact="ACTION"
+ returnType="void"/>
+
+ <operation name="disable"
+ description="Disable all webapps for all engines"
+ impact="ACTION"
+ returnType="boolean"/>
+
+ <operation name="enable"
+ description="Enable all webapps for all engines"
+ impact="ACTION"
+ returnType="boolean"/>
+
+ <operation name="addProxy"
+ description="Add a proxy"
+ impact="ACTION"
+ returnType="void">
+ <parameter name="host"
+ description="Proxy address"
+ type="java.lang.String"/>
+ <parameter name="port"
+ description="Proxy port"
+ type="int"/>
+ </operation>
+
+ <operation name="removeProxy"
+ description="Remove a proxy"
+ impact="ACTION"
+ returnType="void">
+ <parameter name="host"
+ description="Proxy address"
+ type="java.lang.String"/>
+ <parameter name="port"
+ description="Proxy port"
+ type="int"/>
+ </operation>
+
+ </mbean>
+
+</mbeans-descriptors>
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AbstractMCMPHandler.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AbstractMCMPHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AbstractMCMPHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,80 @@
+/*
+ * 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.modcluster.mcmp;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Abstract {@link MCMPHandler} that implements the trivial convenience methods.
+ *
+ * @author Paul Ferraro
+ */
+public abstract class AbstractMCMPHandler implements MCMPHandler
+{
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#addProxy(java.lang.String)
+ */
+ public void addProxy(String address)
+ {
+ AddressPort ap = MCMPUtils.parseAddressPort(address);
+
+ this.addProxy(ap.getAddress(), ap.getPort());
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#addProxy(java.lang.String, int)
+ */
+ public void addProxy(String host, int port)
+ {
+ try
+ {
+ InetAddress address = InetAddress.getByName(host);
+
+ this.addProxy(address, port);
+ }
+ catch (UnknownHostException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ * @see org.jboss.modcluster.mcmp.MCMPHandler#removeProxy(java.lang.String, int)
+ */
+ public void removeProxy(String host, int port)
+ {
+ try
+ {
+ InetAddress address = InetAddress.getByName(host);
+
+ this.removeProxy(address, port);
+ }
+ catch (UnknownHostException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AddressPort.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AddressPort.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/AddressPort.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,81 @@
+/*
+ * 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.modcluster.mcmp;
+
+import java.io.Serializable;
+import java.net.InetAddress;
+
+/**
+ * Simple data object encapsulating an InetAddress and a port.
+ *
+ * @author Brian Stansberry
+ */
+public class AddressPort implements Serializable
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 3835532412744565879L;
+
+ private final InetAddress address;
+ private final int port;
+
+ public AddressPort(InetAddress address, int port)
+ {
+ this.address = address;
+ this.port = port;
+ }
+
+ public InetAddress getAddress()
+ {
+ return this.address;
+ }
+
+ public int getPort()
+ {
+ return this.port;
+ }
+
+ @Override
+ public boolean equals(Object object)
+ {
+ if (!(object instanceof AddressPort)) return false;
+
+ AddressPort ap = (AddressPort) object;
+
+ return (this.port == ap.getPort()) && (((this.address != null) &&
(ap.address != null)) ? this.address.equals(ap.address) : (this.address == ap.address));
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = 17;
+ result += 23 * (this.address == null ? 0 : this.address.hashCode());
+ result += 23 * this.port;
+ return result;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "AddressPort{" + this.address + ":" + this.port +
"}";
+ }
+}
\ No newline at end of file
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPHandler.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPHandler.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,188 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.mcmp;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Set;
+
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+
+/**
+ * Handles communication via MCMP with the httpd side.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public interface MCMPHandler
+{
+ /** Gets this handler's configuration */
+ MCMPHandlerConfiguration getConfiguration();
+
+ /** Initialize the handler with the given list of proxies */
+ void init(List<AddressPort> initialProxies);
+
+ /** Perform any shut down work. */
+ void shutdown();
+
+ /**
+ * Send a request to all healthy proxies.
+ *
+ * @param request the request. Cannot be <code>null</code>
+ **/
+ void sendRequest(MCMPRequest request);
+
+ /**
+ * Send a list of requests to all healthy proxies, with all requests
+ * in the list sent to each proxy before moving on to the next.
+ *
+ * @param requests the requests. Cannot be <code>null</code>
+ */
+ void sendRequests(List<MCMPRequest> requests);
+
+ /**
+ * Add a proxy to the list of those with which this handler communicates.
+ * Communication does not begin until the next call to {@link #status()}.
+ *
+ * @param address a string in the form hostname:port, where the hostname
+ * portion is suitable for passing to
<code>InetAddress.getByHost(...)</code>
+ */
+ void addProxy(String address);
+
+ /**
+ * Add a proxy to the list of those with which this handler communicates.
+ * Communication does not begin until the next call to {@link #status()}.
+ *
+ * @param host the hostname of the proxy; a string suitable for passing to
+ * <code>InetAddress.getByHost(...)</code>
+ * @param port the port on which the proxy listens for MCMP requests
+ */
+ void addProxy(String host, int port);
+
+ /**
+ * Add a proxy to the list of those with which this handler communicates.
+ * Communication does not begin until the next call to {@link #status()}.
+ * <p>
+ * Same as {@link #addProxy(InetAddress, int, boolean) addProxy(address, port,
false}.
+ * </p>
+ *
+ * @param address InetAddress on which the proxy listens for MCMP requests
+ * @param port the port on which the proxy listens for MCMP requests
+ */
+ void addProxy(InetAddress address, int port);
+
+ /**
+ * Add a proxy to the list of those with which this handler communicates.
+ * Communication does not begin until the next call to {@link #status()}.
+ *
+ * @param address InetAddress on which the proxy listens for MCMP requests
+ * @param port the port on which the proxy listens for MCMP requests
+ * @param established <code>true</code> if the proxy should be considered
+ * {@link MCMPServer#isEstablished() established},
+ * <code>false</code> otherwise.
+ */
+ void addProxy(InetAddress address, int port, boolean established);
+
+ /**
+ * Remove a proxy from the list of those with which this handler communicates.
+ * Communication does not end until the next call to {@link #status()}.
+ *
+ * @param host the hostname of the proxy; a string suitable for passing to
+ * <code>InetAddress.getByHost(...)</code>
+ * @param port the port on which the proxy listens for MCMP requests
+ */
+ void removeProxy(String host, int port);
+
+ /**
+ * Remove a proxy from the list of those with which this handler communicates.
+ * Communication does not begin until the next call to {@link #status()}.
+ *
+ * @param address InetAddress on which the proxy listens for MCMP requests
+ * @param port the port on which the proxy listens for MCMP requests
+ */
+ void removeProxy(InetAddress address, int port);
+
+ /**
+ * Get the state of all proxies
+ *
+ * @return a set of status objects indicating the status of this handler's
+ * communication with all proxies.
+ */
+ Set<MCMPServerState> getProxyStates();
+
+ /**
+ * Reset any proxies whose status is {@link MCMPServerState#DOWN DOWN} up to
+ * {@link MCMPServerState#ERROR ERROR}, where the configuration will
+ * be refreshed.
+ */
+ void reset();
+
+ /**
+ * Reset any proxies whose status is {@link MCMPServerState#OK OK} down to
+ * {@link MCMPServerState#ERROR ERROR}, which will trigger a refresh of
+ * their configuration.
+ */
+ void markProxiesInError();
+
+ /**
+ * Convenience method that checks whether the status of all proxies is
+ * {@link MCMPServerState#OK OK}.
+ *
+ * @return <code>true</code> if all proxies are {@link MCMPServerState#OK
OK},
+ * <code>false</code> otherwise
+ */
+ boolean isProxyHealthOK();
+
+ /**
+ * Attempts to determine the address via which this node communicates
+ * with the proxies.
+ *
+ * @return the address, or <code>null</code> if it cannot be determined
+ *
+ * @throws IOException
+ */
+ InetAddress getLocalAddress() throws IOException;
+
+ /**
+ * Sends a {@link MCMPRequestType#DUMP DUMP} request to all proxies,
+ * concatentating their responses into a single string.
+ *
+ * TODO wouldn't a List<String> be better? Let the caller concatenate if
+ * so desired.
+ *
+ * @return the configuration information from all the accessible proxies.
+ */
+ String getProxyConfiguration();
+
+ /**
+ * Perform periodic processing. Update the list of proxies to reflect any
+ * calls to <code>addProxy(...)</code> or
<code>removeProxy(...)</code>.
+ * Attempt to establish communication with any proxies whose state is
+ * {@link MCMPServerState#ERROR ERROR}. If successful and a
+ * {@link ResetRequestSource} has been provided, update the proxy with the
+ * list of requests provided by the source.
+ */
+ void status();
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequest.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequest.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequest.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.mcmp;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.jcip.annotations.Immutable;
+
+/**
+ * Encapsulates the parameters for a request over MCMP.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+@Immutable
+public class MCMPRequest implements Serializable
+{
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 7107364666635260031L;
+
+ private final MCMPRequestType requestType;
+ private final boolean wildcard;
+ private final Map<String, String> parameters;
+
+ /**
+ * Create a new ModClusterRequest.
+ */
+ public MCMPRequest(MCMPRequestType requestType, boolean wildcard, Map<String,
String> parameters)
+ {
+ this.requestType = requestType;
+ this.wildcard = wildcard;
+ this.parameters = Collections.unmodifiableMap(new HashMap<String,
String>(parameters));
+ }
+
+ public MCMPRequestType getRequestType()
+ {
+ return requestType;
+ }
+
+ public boolean isWildcard()
+ {
+ return wildcard;
+ }
+
+ public Map<String, String> getParameters()
+ {
+ return parameters;
+ }
+
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder(getClass().getName());
+ sb.append("{requestType=");
+ sb.append(requestType);
+ sb.append(",wildcard=");
+ sb.append(wildcard);
+ sb.append(",parameters=");
+ synchronized (parameters)
+ {
+ sb.append(parameters);
+ }
+ sb.append("}");
+
+ return sb.toString();
+ }
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequestType.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequestType.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPRequestType.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.mcmp;
+
+/**
+ * Valid types of MCMP requests.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public enum MCMPRequestType
+{
+ CONFIG("CONFIG", true),
+ ENABLE_APP("ENABLE-APP", false),
+ DISABLE_APP("DISABLE-APP", false),
+ STOP_APP("STOP-APP", false),
+ REMOVE_APP("REMOVE-APP", false),
+ STATUS("STATUS", false),
+ INFO("INFO", false),
+ DUMP("DUMP", false);
+
+ private final String command;
+ private final boolean establishesServer;
+
+ private MCMPRequestType(String command, boolean establishesServer)
+ {
+ this.command = command;
+ this.establishesServer = establishesServer;
+ }
+
+ public String getCommand()
+ {
+ return this.command;
+ }
+
+ public boolean getEstablishesServer()
+ {
+ return this.establishesServer;
+ }
+
+ public String toString()
+ {
+ return command;
+ }
+
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServer.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServer.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServer.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,43 @@
+/*
+ * 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.modcluster.mcmp;
+
+import java.net.InetAddress;
+
+/**
+ * Represents a native server that is running the <code>mod_cluster</code>
+ * module and proxying requests to JBoss Web. For example, an Apache httpd
+ * instance. Such an instance represents the server in the Mod Cluster
+ * Management Protocol, with an MCMPHandler acting as the client.
+ *
+ * @author Brian Stansberry
+ */
+public interface MCMPServer
+{
+ InetAddress getAddress();
+
+ int getPort();
+
+ boolean isEstablished();
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServerState.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServerState.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPServerState.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,39 @@
+/*
+ * 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.modcluster.mcmp;
+
+
+/**
+ * Extends {@link MCMPServer} to provide information about the current
+ * state of communications with that server.
+ *
+ * @author Brian Stansberry
+ */
+public interface MCMPServerState extends MCMPServer
+{
+ /** Possible communication states vis a vis the server */
+ public enum State { OK, ERROR, DOWN };
+
+ State getState();
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPUtils.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPUtils.java
(rev 0)
+++ trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/MCMPUtils.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,309 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.mcmp;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.config.BalancerConfiguration;
+import org.jboss.modcluster.config.NodeConfiguration;
+import org.jboss.modcluster.Constants;
+import org.jboss.modcluster.Utils;
+
+/**
+ * Utility methods related to the Mod-Cluster Management Protocol.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public class MCMPUtils
+{
+ public static final int DEFAULT_PORT = 8000;
+
+ private static final MCMPRequest INFO = new MCMPRequest(MCMPRequestType.INFO, false,
new HashMap<String, String>());
+
+ private static final Logger log = Logger.getLogger(MCMPUtils.class);
+
+ /**
+ * The string manager for this package.
+ */
+ private static final StringManager sm = StringManager.getManager(Constants.Package);
+
+
+ public static MCMPRequest createConfigRequest(Engine engine, NodeConfiguration
nodeConfig, BalancerConfiguration balancerConfig)
+ {
+ Connector connector =
Utils.findProxyConnector(engine.getService().findConnectors());
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put("JVMRoute", engine.getJvmRoute());
+ boolean reverseConnection =
+
Boolean.TRUE.equals(IntrospectionUtils.getProperty(connector.getProtocolHandler(),
"reverseConnection"));
+ boolean ssl =
+
Boolean.TRUE.equals(IntrospectionUtils.getProperty(connector.getProtocolHandler(),
"SSLEnabled"));
+ boolean ajp = ((String)
IntrospectionUtils.getProperty(connector.getProtocolHandler(),
"name")).startsWith("ajp-");
+
+ if (reverseConnection) {
+ parameters.put("Reversed", "true");
+ }
+ parameters.put("Host", Utils.getAddress(connector));
+ parameters.put("Port", "" + connector.getPort());
+ if (ajp) {
+ parameters.put("Type", "ajp");
+ } else if (ssl) {
+ parameters.put("Type", "https");
+ } else {
+ parameters.put("Type", "http");
+ }
+
+ // Other configuration parameters
+ if (nodeConfig.getDomain() != null) {
+ parameters.put("Domain", nodeConfig.getDomain());
+ }
+ if (nodeConfig.getFlushPackets()) {
+ parameters.put("flushpackets", "On");
+ }
+ if (nodeConfig.getFlushWait() != -1) {
+ parameters.put("flushwait", "" +
nodeConfig.getFlushWait());
+ }
+ if (nodeConfig.getPing() != -1) {
+ parameters.put("ping", "" + nodeConfig.getPing());
+ }
+ if (nodeConfig.getSmax() != -1) {
+ parameters.put("smax", "" + nodeConfig.getSmax());
+ }
+ if (nodeConfig.getTtl() != -1) {
+ parameters.put("ttl", "" + nodeConfig.getTtl());
+ }
+ if (nodeConfig.getNodeTimeout() != -1) {
+ parameters.put("Timeout", "" +
nodeConfig.getNodeTimeout());
+ }
+ if (nodeConfig.getBalancer() != null) {
+ parameters.put("Balancer", nodeConfig.getBalancer());
+ }
+ if (!balancerConfig.getStickySession()) {
+ parameters.put("StickySession", "No");
+ }
+ if
(!org.apache.catalina.Globals.SESSION_COOKIE_NAME.equals("JSESSIONID")) {
+ parameters.put("StickySessionCookie",
org.apache.catalina.Globals.SESSION_COOKIE_NAME);
+ }
+ if
(!org.apache.catalina.Globals.SESSION_PARAMETER_NAME.equals("jsessionid")) {
+ parameters.put("StickySessionPath",
org.apache.catalina.Globals.SESSION_PARAMETER_NAME);
+ }
+ if (balancerConfig.getStickySessionRemove()) {
+ parameters.put("StickSessionRemove", "Yes");
+ }
+ if (!balancerConfig.getStickySessionForce()) {
+ parameters.put("StickySessionForce", "No");
+ }
+ if (balancerConfig.getWorkerTimeout() != -1) {
+ parameters.put("WaitWorker", "" +
balancerConfig.getWorkerTimeout());
+ }
+ if (balancerConfig.getMaxAttempts() != -1) {
+ parameters.put("Maxattempts", "" +
balancerConfig.getMaxAttempts());
+ }
+
+ return new MCMPRequest(MCMPRequestType.CONFIG, false, parameters);
+ }
+
+ public static MCMPRequest createEnableAppRequest(Context context)
+ {
+ return new MCMPRequest(MCMPRequestType.ENABLE_APP, false,
createContextParameters(context));
+ }
+
+ public static MCMPRequest createDisableAppRequest(Context context)
+ {
+ return new MCMPRequest(MCMPRequestType.DISABLE_APP, false,
createContextParameters(context));
+ }
+
+ public static MCMPRequest createStopAppRequest(Context context)
+ {
+ return new MCMPRequest(MCMPRequestType.STOP_APP, false,
createContextParameters(context));
+ }
+
+ public static MCMPRequest createRemoveAppRequest(Context context)
+ {
+ return new MCMPRequest(MCMPRequestType.REMOVE_APP, false,
createContextParameters(context));
+ }
+
+ public static MCMPRequest createStatusRequest(Engine engine, int lbf)
+ {
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put("JVMRoute", engine.getJvmRoute());
+ parameters.put("Load", String.valueOf(lbf));
+ return new MCMPRequest(MCMPRequestType.STATUS, false, parameters);
+ }
+
+ public static MCMPRequest createStatusRequest(String jvmRoute, int lbf)
+ {
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put("JVMRoute", jvmRoute);
+ parameters.put("Load", String.valueOf(lbf));
+ return new MCMPRequest(MCMPRequestType.STATUS, false, parameters);
+ }
+
+ public static MCMPRequest createEnableEngineRequest(Engine engine)
+ {
+ return new MCMPRequest(MCMPRequestType.ENABLE_APP, true,
createEngineParameters(engine));
+ }
+
+ public static MCMPRequest createDisableEngineRequest(Engine engine)
+ {
+ return new MCMPRequest(MCMPRequestType.DISABLE_APP, true,
createEngineParameters(engine));
+ }
+
+ public static MCMPRequest createRemoveAllRequest(Engine engine)
+ {
+ return new MCMPRequest(MCMPRequestType.REMOVE_APP, true,
createEngineParameters(engine));
+ }
+
+ /**
+ * Reset configuration for a particular proxy following an error.
+ */
+ public static List<MCMPRequest> getResetRequests(Server server,
+ NodeConfiguration nodeConfig, BalancerConfiguration balancerConfig) {
+
+ List<MCMPRequest> requests = new ArrayList<MCMPRequest>();
+ Service[] services = server.findServices();
+ for (int i = 0; i < services.length; i++) {
+ Engine engine = (Engine) services[i].getContainer();
+ if (engine.getJvmRoute() != null)
+ {
+ requests.add(MCMPUtils.createRemoveAllRequest(engine));
+ }
+ requests.add(MCMPUtils.createConfigRequest(engine, nodeConfig,
balancerConfig));
+ Container[] children = engine.findChildren();
+ for (int j = 0; j < children.length; j++) {
+ Container[] children2 = children[j].findChildren();
+ for (int k = 0; k < children2.length; k++) {
+ Context ctx = (Context) children2[k];
+ if (ctx.isStarted())
+ {
+ requests.add(MCMPUtils.createEnableAppRequest(ctx));
+ }
+ }
+ }
+ }
+
+ return requests;
+ }
+
+ public static MCMPRequest getInfoRequest()
+ {
+ return INFO;
+ }
+
+ private static Map<String, String> createEngineParameters(Engine engine)
+ {
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put("JVMRoute", engine.getJvmRoute());
+ return parameters;
+ }
+
+ private static Map<String, String> createContextParameters(Context context)
+ {
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put("JVMRoute", Utils.getJvmRoute(context));
+ parameters.put("Context", ("".equals(context.getPath())) ?
"/" : context.getPath());
+ parameters.put("Alias", Utils.getHost(context));
+ return parameters;
+ }
+
+ public static AddressPort parseAddressPort(String addressPort)
+ {
+ int pos = addressPort.indexOf(':');
+ String host = null;
+ int port = 0;
+ if (pos < 0) {
+ host = addressPort;
+ } else if (pos == 0) {
+ port = Integer.parseInt(addressPort.substring(1));
+ } else {
+ host = addressPort.substring(0, pos);
+ port = Integer.parseInt(addressPort.substring(pos + 1));
+ }
+
+ InetAddress address = null;
+ try {
+ address = InetAddress.getByName(host);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ return new AddressPort(address, port);
+ }
+
+ public static List<AddressPort> parseProxies(String proxyList)
+ {
+ List<AddressPort> proxies = new ArrayList<AddressPort>();
+ if (proxyList != null)
+ {
+ StringTokenizer tok = new StringTokenizer(proxyList, ",");
+ while (tok.hasMoreTokens()) {
+ String token = tok.nextToken().trim();
+ int pos = token.indexOf(':');
+ String address = null;
+ int port = DEFAULT_PORT;
+ if (pos < 0) {
+ address = token;
+ } else if (pos == 0) {
+ port = Integer.parseInt(token.substring(1));
+ } else {
+ address = token.substring(0, pos);
+ port = Integer.parseInt(token.substring(pos + 1));
+ }
+ InetAddress inetAddress = null;
+ try {
+ if (address != null) {
+ inetAddress = InetAddress.getByName(address);
+ }
+ } catch (Exception e) {
+ log.error(sm.getString("modcluster.error.invalidHost", address),
e);
+ continue;
+ }
+ proxies.add(new AddressPort(inetAddress, port));
+ }
+ }
+
+ return proxies;
+ }
+
+ /**
+ * Disable external instantiation.
+ */
+ private MCMPUtils()
+ {
+ }
+
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/ResetRequestSource.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/ResetRequestSource.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/ResetRequestSource.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,45 @@
+/*
+ * 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.modcluster.mcmp;
+
+import java.util.List;
+
+/**
+ * Source for a list of requests that should be sent to an httpd-side
+ * mod_cluster instance when an {@link MCMPHandler} determines that
+ * the httpd-side state needs to be reset.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public interface ResetRequestSource
+{
+ /**
+ * Gets a list of requests that should be sent to an httpd-side
+ * mod_cluster instance when an {@link MCMPHandler} determines that
+ * its state needs to be reset.
+ *
+ * @return a list of requests. Will not return <code>null</code>.
+ */
+ List<MCMPRequest> getResetRequests();
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/DefaultMCMPHandler.java
===================================================================
---
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/DefaultMCMPHandler.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/DefaultMCMPHandler.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,981 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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.modcluster.mcmp.impl;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.jcip.annotations.Immutable;
+
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.UEncoder;
+import org.jboss.logging.Logger;
+import org.jboss.modcluster.Constants;
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+import org.jboss.modcluster.mcmp.AbstractMCMPHandler;
+import org.jboss.modcluster.mcmp.AddressPort;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPRequestType;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+import org.jboss.modcluster.mcmp.MCMPUtils;
+import org.jboss.modcluster.mcmp.ResetRequestSource;
+import org.jboss.modcluster.mcmp.MCMPServerState.State;
+
+/**
+ * Default implementation of {@link MCMPHandler}.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public class DefaultMCMPHandler extends AbstractMCMPHandler
+{
+ protected static Logger log = Logger.getLogger(DefaultMCMPHandler.class);
+
+ /**
+ * The string manager for this package.
+ */
+ protected StringManager sm = StringManager.getManager(Constants.Package);
+
+ // -------------------------------------------------------------- Constants
+
+ // ----------------------------------------------------------------- Fields
+
+ /** Our configuration */
+ private final MCMPHandlerConfiguration config;
+
+ /**
+ * Source for reset requests when we need to reset a proxy.
+ */
+ private final ResetRequestSource resetRequestSource;
+
+ /**
+ * URL encoder used to generate requests bodies.
+ */
+ private UEncoder encoder = new UEncoder();
+
+ /**
+ * Proxies.
+ */
+ private volatile Proxy[] proxies = new Proxy[0];
+
+ /**
+ * Add proxy list.
+ */
+ private List<Proxy> addProxies = new ArrayList<Proxy>();
+
+ /**
+ * Remove proxy list.
+ */
+ private List<Proxy> removeProxies = new ArrayList<Proxy>();
+
+ /**
+ * Socket factory.
+ */
+ private JSSESocketFactory sslSocketFactory = null;
+
+ /** Initialization completion flag */
+ private boolean init;
+
+ // ----------------------------------------------------------- Constructors
+
+ public DefaultMCMPHandler(MCMPHandlerConfiguration config, ResetRequestSource source)
+ {
+ this.config = config;
+ this.resetRequestSource = source;
+
+ if (this.config.isSsl())
+ {
+ this.sslSocketFactory = new JSSESocketFactory(this.config);
+ }
+ }
+
+ // -------------------------------------------------------------- Properties
+
+ public ResetRequestSource getResetRequestSource()
+ {
+ return this.resetRequestSource;
+ }
+
+ // ------------------------------------------------------------ MCMPHandler
+
+ public MCMPHandlerConfiguration getConfiguration()
+ {
+ return this.config;
+ }
+
+ public synchronized void init(List<AddressPort> initialProxies)
+ {
+ if (this.init) return;
+
+ if (initialProxies != null)
+ {
+ for (AddressPort initialProxy: initialProxies)
+ {
+ this.addProxy(initialProxy.getAddress(), initialProxy.getPort());
+ }
+ }
+
+ this.status(false);
+
+ this.init = true;
+ }
+
+ public synchronized void shutdown()
+ {
+ if (!this.init) return;
+
+ for (Proxy proxy : this.proxies)
+ {
+ synchronized (proxy)
+ {
+ proxy.closeConnection();
+ }
+ }
+
+ this.init = false;
+ }
+
+ public synchronized void addProxy(InetAddress address, int port)
+ {
+ this.addProxyInternal(address, port);
+ }
+
+ private synchronized Proxy addProxyInternal(InetAddress address, int port)
+ {
+ Proxy proxy = new Proxy(address, port, this.sslSocketFactory,
this.config.getSocketTimeout());
+
+ for (Proxy candidate: this.proxies)
+ {
+ if (candidate.equals(proxy)) return candidate;
+ }
+ for (Proxy candidate: this.addProxies)
+ {
+ if (candidate.equals(proxy)) return candidate;
+ }
+ for (Proxy candidate: this.removeProxies)
+ {
+ if (candidate.equals(proxy)) return candidate;
+ }
+
+ proxy.setState(Proxy.State.ERROR);
+
+ this.addProxies.add(proxy);
+
+ return proxy;
+ }
+
+ public synchronized void addProxy(InetAddress address, int port, boolean established)
+ {
+ Proxy proxy = this.addProxyInternal(address, port);
+ proxy.setEstablished(established);
+ }
+
+ public synchronized void removeProxy(InetAddress address, int port)
+ {
+ Proxy proxy = new Proxy(address, port, this.sslSocketFactory,
this.config.getSocketTimeout());
+ this.removeProxies.add(proxy);
+ }
+
+ public synchronized Set<MCMPServerState> getProxyStates()
+ {
+ Proxy[] local = this.proxies;
+
+ if (local == null) return Collections.emptySet();
+
+ Set<MCMPServerState> result = new
HashSet<MCMPServerState>(local.length);
+
+ for (Proxy proxy : local)
+ {
+ result.add(new MCMPServerStateImpl(proxy));
+ }
+
+ return result;
+ }
+
+ public synchronized boolean isProxyHealthOK()
+ {
+ boolean ok = true;
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ if (proxy.getState() != MCMPServerState.State.OK)
+ {
+ ok = false;
+ break;
+ }
+ }
+ return ok;
+ }
+
+ public synchronized void markProxiesInError()
+ {
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ synchronized (proxy)
+ {
+ if (proxy.getState() == State.OK)
+ {
+ proxy.setState(Proxy.State.ERROR);
+ }
+ }
+ }
+ }
+
+ /**
+ * Retrieves the full proxy configuration. To be used through JMX or similar.
+ *
+ * response: HTTP/1.1 200 OK
+ * response:
+ * node: [1:1] JVMRoute: node1 Domain: [bla] Host: 127.0.0.1 Port: 8009 Type: ajp
+ * host: 1 [] vhost: 1 node: 1
+ * context: 1 [/] vhost: 1 node: 1 status: 1
+ * context: 2 [/myapp] vhost: 1 node: 1 status: 1
+ * context: 3 [/host-manager] vhost: 1 node: 1 status: 1
+ * context: 4 [/docs] vhost: 1 node: 1 status: 1
+ * context: 5 [/manager] vhost: 1 node: 1 status: 1
+ *
+ * @return the proxy confguration
+ */
+ public String getProxyConfiguration()
+ {
+ Map<String, String> parameters = new HashMap<String, String>();
+ // Send DUMP * request
+ Proxy[] local = this.proxies;
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < local.length; i++)
+ {
+ result.append("Proxy[").append(i).append("]:
[").append(local[i].getAddress())
+ .append(':').append(local[i].getPort()).append("]:
\r\n");
+ synchronized (local[i])
+ {
+ result.append(this.sendRequest(new MCMPRequest(MCMPRequestType.DUMP, true,
parameters), local[i]));
+ }
+ result.append("\r\n");
+ }
+ return result.toString();
+ }
+
+ public InetAddress getLocalAddress() throws IOException
+ {
+ IOException firstException = null;
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ try
+ {
+ return proxy.getConnection().getInetAddress();
+ }
+ catch (IOException e)
+ {
+ // Cache the exception in case no other connection works,
+ // but keep trying
+ if (firstException == null)
+ {
+ firstException = e;
+ }
+ }
+ }
+
+ if (firstException != null) throw firstException;
+
+ // We get here if there are no proxies
+ return null;
+ }
+
+ /**
+ * Reset a DOWN connection to the proxy up to ERROR, where the configuration will
+ * be refreshed. To be used through JMX or similar.
+ */
+ public void reset()
+ {
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ synchronized (proxy)
+ {
+ if (proxy.getState() == Proxy.State.DOWN)
+ {
+ proxy.setState(Proxy.State.ERROR);
+ }
+ }
+ }
+ }
+
+ /**
+ * Send a periodic status request. If in error state, the listener will attempt to
refresh
+ * the configuration on the front end server.
+ *
+ * @param engine
+ */
+ public synchronized void status()
+ {
+ if (!this.init) return;
+
+ this.status(true);
+ }
+
+ private synchronized void status(boolean sendResetRequests)
+ {
+ this.processPendingDiscoveryEvents();
+
+ // Attempt to reset any proxies in error
+ List<MCMPRequest> resetRequests = null;
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ synchronized (proxy)
+ {
+ if (proxy.getState() == Proxy.State.ERROR)
+ {
+ proxy.setState(Proxy.State.OK);
+
+ this.sendRequest(MCMPUtils.getInfoRequest(), proxy);
+
+ if (proxy.getState() == Proxy.State.OK)
+ {
+ // We recovered above; if we get another IOException
+ // we should log it
+ proxy.setIoExceptionLogged(false);
+
+ if (sendResetRequests)
+ {
+ if (resetRequests == null)
+ {
+ resetRequests = this.resetRequestSource.getResetRequests();
+ }
+
+ for (MCMPRequest request : resetRequests)
+ {
+ this.sendRequest(request, proxy);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Send HTTP request, with the specified list of parameters. If an IO error occurs,
the error state will
+ * be set. If the front end server reports an error, will mark as error Proxy.State.
Other unexpected exceptions
+ * will be thrown and the error state will be set.
+ *
+ * @param command
+ * @param wildcard
+ * @param parameters
+ * @return the response body as a String; null if in error state or a normal error
occurs
+ */
+ public void sendRequest(MCMPRequest request)
+ {
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ this.sendRequest(request, proxy);
+ }
+ }
+
+ public void sendRequests(List<MCMPRequest> requests)
+ {
+ Proxy[] local = this.proxies;
+ for (Proxy proxy : local)
+ {
+ for (MCMPRequest request : requests)
+ {
+ this.sendRequest(request, proxy);
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------- Private
+
+ private synchronized void processPendingDiscoveryEvents()
+ {
+ // Check to add or remove proxies, and rebuild a new list if needed
+ if (!this.addProxies.isEmpty() || !this.removeProxies.isEmpty())
+ {
+ Set<Proxy> currentProxies = new HashSet<Proxy>();
+
+ for (Proxy proxy : this.proxies)
+ {
+ currentProxies.add(proxy);
+ }
+
+ for (Proxy proxy: this.addProxies)
+ {
+ currentProxies.add(proxy);
+ }
+ for (Proxy proxy: this.removeProxies)
+ {
+ currentProxies.remove(proxy);
+ }
+ this.addProxies.clear();
+ this.removeProxies.clear();
+ this.proxies = currentProxies.toArray(new Proxy[0]);
+
+ // Reset all connections
+ for (Proxy proxy : this.proxies)
+ {
+ proxy.closeConnection();
+ }
+ }
+ }
+
+ private synchronized String sendRequest(MCMPRequest request, Proxy proxy)
+ {
+ // If there was an error, do nothing until the next periodic event, where the whole
configuration
+ // will be refreshed
+ if (proxy.getState() != Proxy.State.OK) return null;
+
+ BufferedReader reader = null;
+ BufferedWriter writer = null;
+ CharChunk body = null;
+
+ String command = request.getRequestType().getCommand();
+ boolean wildcard = request.isWildcard();
+ Map<String, String> parameters = request.getParameters();
+
+ // First, encode the POST body
+ try
+ {
+ body = this.encoder.encodeURL("", 0, 0);
+ body.recycle();
+
+ Iterator<String> keys = parameters.keySet().iterator();
+
+ while (keys.hasNext())
+ {
+ String key = keys.next();
+ String value = parameters.get(key);
+
+ if (value == null)
+ {
+ throw new
IllegalArgumentException(this.sm.getString("modcluster.error.nullAttribute",
key));
+ }
+
+ body.append(this.encoder.encodeURL(key, 0, key.length()));
+ body.append('=');
+ body.append(this.encoder.encodeURL(value, 0, value.length()));
+
+ if (keys.hasNext())
+ {
+ body.append('&');
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ if (body != null)
+ {
+ body.recycle();
+ }
+ // Error encoding URL, should not happen
+ throw new IllegalArgumentException(e);
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace(this.sm.getString("modcluster.request", command, new
Boolean(wildcard), proxy));
+ }
+
+ synchronized (proxy)
+ {
+ try
+ {
+ // Then, connect to the proxy
+ proxy.getConnection();
+ writer = proxy.getConnectionWriter();
+ // Check connection to see if it is still alive (not really allowed,
+ // but httpd deals with the extra CRLF)
+ try
+ {
+ writer.write("\r\n");
+ writer.flush();
+ }
+ catch (IOException e)
+ {
+ // Get a new connection; if it fails this second time, it is an error
+ proxy.closeConnection();
+ proxy.getConnection();
+ writer = proxy.getConnectionWriter();
+ }
+
+ // Generate and write request
+ String url = this.config.getProxyURL();
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append(command).append(" ");
+
+ if (url != null)
+ {
+ builder.append(url);
+ }
+
+ if (builder.charAt(builder.length() - 1) != '/')
+ {
+ builder.append('/');
+ }
+
+ if (wildcard)
+ {
+ builder.append('*');
+ }
+
+ builder.append(" HTTP/1.0");
+
+ writer.write(builder.toString());
+ writer.write("\r\n");
+ writer.write("Content-Length: " + body.getLength() +
"\r\n");
+ writer.write("User-Agent: ClusterListener/1.0\r\n");
+ writer.write("Connection: Keep-Alive\r\n");
+ writer.write("\r\n");
+ writer.write(body.getBuffer(), body.getStart(), body.getLength());
+ writer.write("\r\n");
+ writer.flush();
+
+ // Read the response to a string
+ reader = proxy.getConnectionReader();
+ // Read the first response line and skip the rest of the HTTP header
+ String responseStatus = reader.readLine();
+ // Parse the line, which is formed like HTTP/1.x YYY Message
+ int status = 500;
+ String version = "0";
+ String message = null;
+ String errorType = null;
+ int contentLength = 0;
+ if (responseStatus != null)
+ {
+ try
+ {
+ responseStatus = responseStatus.substring(responseStatus.indexOf('
') + 1, responseStatus.indexOf(
+ ' ', responseStatus.indexOf(' ') + 1));
+ status = Integer.parseInt(responseStatus);
+ String header = reader.readLine();
+ while (!"".equals(header))
+ {
+ int colon = header.indexOf(':');
+ String headerName = header.substring(0, colon).trim();
+ String headerValue = header.substring(colon + 1).trim();
+ if ("version".equalsIgnoreCase(headerName))
+ {
+ version = headerValue;
+ }
+ else if ("type".equalsIgnoreCase(headerName))
+ {
+ errorType = headerValue;
+ }
+ else if ("mess".equalsIgnoreCase(headerName))
+ {
+ message = headerValue;
+ }
+ else if ("content-length".equalsIgnoreCase(headerName))
+ {
+ contentLength = Integer.parseInt(headerValue);
+ }
+ header = reader.readLine();
+ }
+ }
+ catch (Exception e)
+ {
+ log.info(this.sm.getString("modcluster.error.parse",
command), e);
+ }
+ }
+
+ // Mark as error if the front end server did not return 200; the
configuration will
+ // be refreshed during the next periodic event
+ if (status == 200)
+ {
+
+ // We know the request succeeded, so if appropriate
+ // mark the proxy as established before any possible
+ // later exception happens
+ if (request.getRequestType().getEstablishesServer())
+ {
+ proxy.setEstablished(true);
+ }
+
+ // Read the request body
+ StringBuilder result = new StringBuilder();
+ if (contentLength > 0)
+ {
+ int thisTime = contentLength;
+ char[] buf = new char[512];
+ while (contentLength > 0)
+ {
+ thisTime = (contentLength > buf.length) ? buf.length :
contentLength;
+ int n = reader.read(buf, 0, thisTime);
+
+ if (n <= 0) break;
+
+ result.append(buf, 0, n);
+ contentLength -= n;
+ }
+ }
+
+ return result.toString();
+ }
+
+ if ("SYNTAX".equals(errorType))
+ {
+ // Syntax error means the protocol is incorrect, which cannot be
automatically fixed
+ proxy.setState(Proxy.State.DOWN);
+ log.error(this.sm.getString("modcluster.error.syntax", command,
proxy, errorType, message));
+ }
+ else
+ {
+ proxy.setState(Proxy.State.ERROR);
+ log.error(this.sm.getString("modcluster.error.other", command,
proxy, errorType, message));
+ }
+ }
+ catch (IOException e)
+ {
+ // Most likely this is a connection error with the proxy
+ proxy.setState(Proxy.State.ERROR);
+
+ // Log it only if we haven't done so already. Don't spam the log
+ if (proxy.isIoExceptionLogged() == false)
+ {
+ log.info(this.sm.getString("modcluster.error.io", command,
proxy), e);
+ proxy.setIoExceptionLogged(true);
+ }
+ }
+ finally
+ {
+ // If there's an error of any sort, or if the proxy did not return 200,
it is an error
+ if (proxy.getState() != Proxy.State.OK)
+ {
+ proxy.closeConnection();
+ }
+ }
+ }
+
+ return null;
+
+ }
+
+ /**
+ * This class represents a front-end httpd server.
+ */
+ private static class Proxy implements MCMPServerState
+ {
+ public static final int DEFAULT_PORT = 8000;
+
+ private final InetAddress address;
+ private final int port;
+ private final JSSESocketFactory sslSocketFactory;
+ private final int socketTimeout;
+
+ private volatile State state = State.OK;
+ private volatile boolean established;
+
+ private Socket connection;
+ private BufferedReader connectionReader;
+ private BufferedWriter connectionWriter;
+ private boolean ioExceptionLogged;
+
+ /**
+ * The string manager for this package.
+ */
+ private final StringManager sm = StringManager.getManager(Constants.Package);
+
+ Proxy(InetAddress address, int port, JSSESocketFactory sslSocketFactory, int
socketTimeout)
+ {
+ if (address == null)
+ {
+ throw new
IllegalArgumentException(this.sm.getString("modcluster.error.iae.null",
"address"));
+ }
+ if (port <= 0)
+ {
+ throw new
IllegalArgumentException(this.sm.getString("modcluster.error.iae.invalid", new
Integer(port), "port"));
+ }
+
+ this.address = address;
+ this.port = port;
+ this.sslSocketFactory = sslSocketFactory;
+ this.socketTimeout = socketTimeout;
+ }
+
+ // -------------------------------------------- MCMPServerConnectionState
+
+ public synchronized State getState()
+ {
+ return this.state;
+ }
+
+ // ----------------------------------------------------------- MCMPServer
+
+ public InetAddress getAddress()
+ {
+ return this.address;
+ }
+
+ public int getPort()
+ {
+ return this.port;
+ }
+
+ public boolean isEstablished()
+ {
+ return this.established;
+ }
+
+ // ------------------------------------------------------------ Overrides
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ if (this.address != null)
+ {
+ builder.append(this.address.getHostAddress());
+ }
+
+ return builder.append(':').append(this.port).toString();
+ }
+
+ @Override
+ public boolean equals(Object object)
+ {
+ if (!(object instanceof Proxy)) return false;
+
+ Proxy proxy = (Proxy) object;
+ InetAddress address = proxy.address;
+
+ return (this.port == proxy.port) && ((this.address != null) &&
(address != null) ? this.address.equals(address) : this.address == address);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = 17;
+ result += 23 * (this.address == null ? 0 : this.address.hashCode());
+ result += 23 * this.port;
+ return result;
+ }
+
+ // -------------------------------------------------------------- Private
+
+ synchronized void setState(State state)
+ {
+ if (state == null)
+ throw new
IllegalArgumentException(this.sm.getString("modcluster.error.iae.null",
"state"));
+ this.state = state;
+ }
+
+ synchronized void setEstablished(boolean established)
+ {
+ this.established = established;
+ }
+
+ /**
+ * Return a reader to the proxy.
+ */
+ synchronized Socket getConnection() throws IOException
+ {
+ if (this.connection == null || this.connection.isClosed())
+ {
+ if (this.sslSocketFactory != null)
+ {
+ this.connection = this.sslSocketFactory.createSocket(this.address,
this.port);
+ }
+ else
+ {
+ this.connection = new Socket(this.address, this.port);
+ }
+ this.connection.setSoTimeout(this.socketTimeout);
+ }
+ return this.connection;
+ }
+
+ /**
+ * Return a reader to the proxy.
+ */
+ synchronized BufferedReader getConnectionReader() throws IOException
+ {
+ if (this.connectionReader == null)
+ {
+ this.connectionReader = new BufferedReader(new
InputStreamReader(this.connection.getInputStream()));
+ }
+ return this.connectionReader;
+ }
+
+ /**
+ * Return a writer to the proxy.
+ */
+ synchronized BufferedWriter getConnectionWriter() throws IOException
+ {
+ if (this.connectionWriter == null)
+ {
+ this.connectionWriter = new BufferedWriter(new
OutputStreamWriter(this.connection.getOutputStream()));
+ }
+ return this.connectionWriter;
+ }
+
+ /**
+ * Close connection.
+ */
+ synchronized void closeConnection()
+ {
+ try
+ {
+ if (this.connectionReader != null)
+ {
+ this.connectionReader.close();
+ }
+ }
+ catch (IOException e)
+ {
+ // Ignore
+ }
+ this.connectionReader = null;
+ try
+ {
+ if (this.connectionWriter != null)
+ {
+ this.connectionWriter.close();
+ }
+ }
+ catch (IOException e)
+ {
+ // Ignore
+ }
+ this.connectionWriter = null;
+ try
+ {
+ if (this.connection != null)
+ {
+ this.connection.close();
+ }
+ }
+ catch (IOException e)
+ {
+ // Ignore
+ }
+ this.connection = null;
+ }
+
+ boolean isIoExceptionLogged()
+ {
+ return this.ioExceptionLogged;
+ }
+
+ void setIoExceptionLogged(boolean ioErrorLogged)
+ {
+ this.ioExceptionLogged = ioErrorLogged;
+ }
+ }
+
+ @Immutable
+ private static class MCMPServerStateImpl implements MCMPServerState, Serializable
+ {
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 5219680414337319908L;
+
+ private final State state;
+ private final InetAddress address;
+ private final int port;
+ private final boolean established;
+
+ MCMPServerStateImpl(MCMPServerState source)
+ {
+ this.state = source.getState();
+ this.address = source.getAddress();
+ this.port = source.getPort();
+ this.established = source.isEstablished();
+ }
+
+ public State getState()
+ {
+ return this.state;
+ }
+
+ public InetAddress getAddress()
+ {
+ return this.address;
+ }
+
+ public int getPort()
+ {
+ return this.port;
+ }
+
+ public boolean isEstablished()
+ {
+ return this.established;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+
+ if (obj instanceof MCMPServerStateImpl)
+ {
+ MCMPServerStateImpl other = (MCMPServerStateImpl) obj;
+ return (this.port == other.port && this.address.equals(other.address)
&& this.state == other.state && this.established == other.established);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = 17;
+ result += 23 * (this.address == null ? 0 : this.address.hashCode());
+ result += 23 * this.port;
+ result += 23 * this.state.hashCode();
+ result += 23 * (this.established ? 0 : 1);
+ return result;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder(this.getClass().getSimpleName());
+ sb.append("{address=").append(this.address)
+ .append(",port=").append(this.port)
+ .append(",state=").append(this.state)
+
.append(",established").append(this.established).append("}");
+ return sb.toString();
+ }
+ }
+}
Added: trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSEKeyManager.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSEKeyManager.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSEKeyManager.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *
http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.modcluster.mcmp.impl;
+
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.X509KeyManager;
+
+/**
+ * X509KeyManager which allows selection of a specific keypair and certificate
+ * chain (identified by their keystore alias name) to be used by the server to
+ * authenticate itself to SSL clients.
+ *
+ * @author Jan Luehe
+ */
+public final class JSSEKeyManager implements X509KeyManager {
+
+ private X509KeyManager delegate;
+ private String serverKeyAlias;
+
+ /**
+ * Constructor.
+ *
+ * @param mgr The X509KeyManager used as a delegate
+ * @param serverKeyAlias The alias name of the server's keypair and
+ * supporting certificate chain
+ */
+ public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) {
+ this.delegate = mgr;
+ this.serverKeyAlias = serverKeyAlias;
+ }
+
+ /**
+ * Choose an alias to authenticate the client side of a secure socket,
+ * given the public key type and the list of certificate issuer authorities
+ * recognized by the peer (if any).
+ *
+ * @param keyType The key algorithm type name(s), ordered with the
+ * most-preferred key type first
+ * @param issuers The list of acceptable CA issuer subject names, or null
+ * if it does not matter which issuers are used
+ * @param socket The socket to be used for this connection. This parameter
+ * can be null, in which case this method will return the most generic
+ * alias to use
+ *
+ * @return The alias name for the desired key, or null if there are no
+ * matches
+ */
+ public String chooseClientAlias(String[] keyType, Principal[] issuers,
+ Socket socket) {
+ return delegate.chooseClientAlias(keyType, issuers, socket);
+ }
+
+ /**
+ * Returns this key manager's server key alias that was provided in the
+ * constructor.
+ *
+ * @param keyType The key algorithm type name (ignored)
+ * @param issuers The list of acceptable CA issuer subject names, or null
+ * if it does not matter which issuers are used (ignored)
+ * @param socket The socket to be used for this connection. This parameter
+ * can be null, in which case this method will return the most generic
+ * alias to use (ignored)
+ *
+ * @return Alias name for the desired key
+ */
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ return serverKeyAlias;
+ }
+
+ /**
+ * Returns the certificate chain associated with the given alias.
+ *
+ * @param alias The alias name
+ *
+ * @return Certificate chain (ordered with the user's certificate first
+ * and the root certificate authority last), or null if the alias can't be
+ * found
+ */
+ public X509Certificate[] getCertificateChain(String alias) {
+ return delegate.getCertificateChain(alias);
+ }
+
+ /**
+ * Get the matching aliases for authenticating the client side of a secure
+ * socket, given the public key type and the list of certificate issuer
+ * authorities recognized by the peer (if any).
+ *
+ * @param keyType The key algorithm type name
+ * @param issuers The list of acceptable CA issuer subject names, or null
+ * if it does not matter which issuers are used
+ *
+ * @return Array of the matching alias names, or null if there were no
+ * matches
+ */
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return delegate.getClientAliases(keyType, issuers);
+ }
+
+ /**
+ * Get the matching aliases for authenticating the server side of a secure
+ * socket, given the public key type and the list of certificate issuer
+ * authorities recognized by the peer (if any).
+ *
+ * @param keyType The key algorithm type name
+ * @param issuers The list of acceptable CA issuer subject names, or null
+ * if it does not matter which issuers are used
+ *
+ * @return Array of the matching alias names, or null if there were no
+ * matches
+ */
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return delegate.getServerAliases(keyType, issuers);
+ }
+
+ /**
+ * Returns the key associated with the given alias.
+ *
+ * @param alias The alias name
+ *
+ * @return The requested key, or null if the alias can't be found
+ */
+ public PrivateKey getPrivateKey(String alias) {
+ return delegate.getPrivateKey(alias);
+ }
+}
Added:
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSESocketFactory.java
===================================================================
--- trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSESocketFactory.java
(rev 0)
+++
trunk/mod_cluster/src/main/java/org/jboss/modcluster/mcmp/impl/JSSESocketFactory.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,552 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *
http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.modcluster.mcmp.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509CertSelector;
+import java.util.Collection;
+import java.util.Vector;
+
+import javax.net.ssl.CertPathTrustManagerParameters;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+
+import org.apache.tomcat.util.res.StringManager;
+import org.jboss.modcluster.config.SSLConfiguration;
+
+/*
+ 1. Make the JSSE's jars available, either as an installed
+ extension (copy them into jre/lib/ext) or by adding
+ them to the Tomcat classpath.
+ 2. keytool -genkey -alias tomcat -keyalg RSA
+ Use "changeit" as password ( this is the default we use )
+ */
+
+/**
+ * SSL server socket factory. It _requires_ a valid RSA key and
+ * JSSE.
+ *
+ * @author Harish Prabandham
+ * @author Costin Manolache
+ * @author Stefan Freyr Stefansson
+ * @author EKR -- renamed to JSSESocketFactory
+ * @author Jan Luehe
+ * @author Bill Barker
+ */
+public class JSSESocketFactory {
+
+ private static StringManager sm =
+ StringManager.getManager("org.apache.tomcat.util.net.jsse.res");
+
+ static org.jboss.logging.Logger log =
+ org.jboss.logging.Logger.getLogger(JSSESocketFactory.class);
+
+ protected boolean initialized;
+ //protected String clientAuth = "false";
+ protected SSLSocketFactory sslProxy = null;
+ protected String[] enabledCiphers;
+ protected SSLConfiguration config = null;
+
+ /**
+ * Flag to state that we require client authentication.
+ */
+ //protected boolean requireClientAuth = false;
+
+ /**
+ * Flag to state that we would like client authentication.
+ */
+ //protected boolean wantClientAuth = false;
+
+
+ public JSSESocketFactory (SSLConfiguration config) {
+ this.config = config;
+ }
+
+ public Socket createSocket (InetAddress ifAddress, int port)
+ throws IOException
+ {
+ if (!initialized) init();
+ Socket socket = sslProxy.createSocket(ifAddress, port);
+ initSocket(socket);
+ return socket;
+ }
+
+ public void handshake(Socket sock) throws IOException {
+ ((SSLSocket)sock).startHandshake();
+ }
+
+ /*
+ * Determines the SSL cipher suites to be enabled.
+ *
+ * @param requestedCiphers Comma-separated list of requested ciphers
+ * @param supportedCiphers Array of supported ciphers
+ *
+ * @return Array of SSL cipher suites to be enabled, or null if none of the
+ * requested ciphers are supported
+ */
+ protected String[] getEnabledCiphers(String requestedCiphers,
+ String[] supportedCiphers) {
+
+ String[] enabledCiphers = null;
+
+ if (requestedCiphers != null) {
+ Vector<String> vec = null;
+ String cipher = requestedCiphers;
+ int index = requestedCiphers.indexOf(',');
+ if (index != -1) {
+ int fromIndex = 0;
+ while (index != -1) {
+ cipher = requestedCiphers.substring(fromIndex, index).trim();
+ if (cipher.length() > 0) {
+ /*
+ * Check to see if the requested cipher is among the
+ * supported ciphers, i.e., may be enabled
+ */
+ for (int i=0; supportedCiphers != null
+ && i<supportedCiphers.length; i++) {
+ if (supportedCiphers[i].equals(cipher)) {
+ if (vec == null) {
+ vec = new Vector<String>();
+ }
+ vec.addElement(cipher);
+ break;
+ }
+ }
+ }
+ fromIndex = index+1;
+ index = requestedCiphers.indexOf(',', fromIndex);
+ } // while
+ cipher = requestedCiphers.substring(fromIndex);
+ }
+
+ if (cipher != null) {
+ cipher = cipher.trim();
+ if (cipher.length() > 0) {
+ /*
+ * Check to see if the requested cipher is among the
+ * supported ciphers, i.e., may be enabled
+ */
+ for (int i=0; supportedCiphers != null
+ && i<supportedCiphers.length; i++) {
+ if (supportedCiphers[i].equals(cipher)) {
+ if (vec == null) {
+ vec = new Vector<String>();
+ }
+ vec.addElement(cipher);
+ break;
+ }
+ }
+ }
+ }
+
+ if (vec != null) {
+ enabledCiphers = new String[vec.size()];
+ vec.copyInto(enabledCiphers);
+ }
+ } else {
+ enabledCiphers = sslProxy.getDefaultCipherSuites();
+ }
+
+ return enabledCiphers;
+ }
+
+ /*
+ * Gets the SSL server's keystore.
+ */
+ protected KeyStore getKeystore(String type, String provider, String pass)
+ throws IOException {
+ return getStore(type, provider, config.getSslKeyStore(), pass);
+ }
+
+ /*
+ * Gets the SSL server's truststore.
+ */
+ protected KeyStore getTrustStore(String keystoreType,
+ String keystoreProvider) throws IOException {
+ KeyStore trustStore = null;
+
+ String truststorePassword = config.getSslTrustStorePassword();
+ if( truststorePassword == null ) {
+ truststorePassword = config.getSslKeyStorePass();
+ } else if (truststorePassword.equals("")) {
+ truststorePassword = null;
+ }
+ String truststoreType = config.getSslTrustStoreType();
+ if(truststoreType == null) {
+ truststoreType = keystoreType;
+ }
+ String truststoreProvider = config.getSslTrustStoreProvider();
+ if (truststoreProvider == null) {
+ truststoreProvider = keystoreProvider;
+ }
+
+ if (config.getSslTrustStore() != null){
+ trustStore = getStore(truststoreType, truststoreProvider,
+ config.getSslTrustStore(), truststorePassword);
+ }
+
+ return trustStore;
+ }
+
+ /*
+ * Gets the key- or truststore with the specified type, path, and password.
+ */
+ private KeyStore getStore(String type, String provider, String path,
+ String pass) throws IOException {
+
+ KeyStore ks = null;
+ InputStream istream = null;
+ try {
+ if (provider == null) {
+ ks = KeyStore.getInstance(type);
+ } else {
+ ks = KeyStore.getInstance(type, provider);
+ }
+ if(!("PKCS11".equalsIgnoreCase(type) ||
"".equalsIgnoreCase(path))) {
+ File keyStoreFile = new File(path);
+ if (!keyStoreFile.isAbsolute()) {
+ keyStoreFile = new
File(System.getProperty("catalina.base"),
+ path);
+ }
+ istream = new FileInputStream(keyStoreFile);
+ }
+
+ if (pass == null)
+ ks.load(istream, null);
+ else
+ ks.load(istream, pass.toCharArray());
+ } catch (FileNotFoundException fnfe) {
+ log.error(sm.getString("jsse.keystore_load_failed", type, path,
+ fnfe.getMessage()), fnfe);
+ throw fnfe;
+ } catch (IOException ioe) {
+ log.error(sm.getString("jsse.keystore_load_failed", type, path,
+ ioe.getMessage()), ioe);
+ throw ioe;
+ } catch(Exception ex) {
+ String msg = sm.getString("jsse.keystore_load_failed", type, path,
+ ex.getMessage());
+ log.error(msg, ex);
+ throw new IOException(msg);
+ } finally {
+ if (istream != null) {
+ try {
+ istream.close();
+ } catch (IOException ioe) {
+ // Do nothing
+ }
+ }
+ }
+
+ return ks;
+ }
+
+ /**
+ * Reads the keystore and initializes the SSL socket factory.
+ */
+ void init() throws IOException {
+ try {
+
+ /**
+ String clientAuthStr = (String) attributes.get("clientauth");
+ if("true".equalsIgnoreCase(clientAuthStr) ||
+ "yes".equalsIgnoreCase(clientAuthStr)) {
+ requireClientAuth = true;
+ } else if("want".equalsIgnoreCase(clientAuthStr)) {
+ wantClientAuth = true;
+ }*/
+
+ // Create and init SSLContext
+ SSLContext context = SSLContext.getInstance(config.getSslProtocol());
+ context.init(getKeyManagers(config.getSslKeyStoreType(),
+ config.getSslKeyStoreProvider(),
+ config.getSslCertificateEncodingAlgorithm(),
+ config.getSslKeyAlias()),
+ getTrustManagers(config.getSslKeyStoreType(),
config.getSslKeyStoreProvider(),
+ config.getSslTrustAlgorithm()),
+ new SecureRandom());
+
+ // create proxy
+ sslProxy = context.getSocketFactory();
+
+ // Determine which cipher suites to enable
+ enabledCiphers = getEnabledCiphers(config.getSslCiphers(),
+ sslProxy.getSupportedCipherSuites());
+
+ } catch(Exception e) {
+ if( e instanceof IOException )
+ throw (IOException)e;
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * Gets the initialized key managers.
+ */
+ protected KeyManager[] getKeyManagers(String keystoreType,
+ String keystoreProvider,
+ String algorithm,
+ String keyAlias)
+ throws Exception {
+
+ KeyManager[] kms = null;
+
+ KeyStore ks = getKeystore(keystoreType, keystoreProvider,
config.getSslKeyStorePass());
+ if (keyAlias != null && !ks.isKeyEntry(keyAlias)) {
+ throw new IOException(sm.getString("jsse.alias_no_key_entry",
keyAlias));
+ }
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
+ kmf.init(ks, config.getSslKeyStorePass().toCharArray());
+
+ kms = kmf.getKeyManagers();
+ if (keyAlias != null) {
+ if ("JKS".equals(keystoreType)) {
+ keyAlias = keyAlias.toLowerCase();
+ }
+ for(int i=0; i<kms.length; i++) {
+ kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], keyAlias);
+ }
+ }
+
+ return kms;
+ }
+
+ /**
+ * Gets the intialized trust managers.
+ */
+ protected TrustManager[] getTrustManagers(String keystoreType,
+ String keystoreProvider, String algorithm)
+ throws Exception {
+ TrustManager[] tms = null;
+
+ KeyStore trustStore = getTrustStore(keystoreType, keystoreProvider);
+ if (trustStore != null) {
+ if (config.getSslCrlFile() == null) {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ tmf.init(trustStore);
+ tms = tmf.getTrustManagers();
+ } else {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+ CertPathParameters params = getParameters(algorithm,
config.getSslCrlFile(), trustStore);
+ ManagerFactoryParameters mfp = new
CertPathTrustManagerParameters(params);
+ tmf.init(mfp);
+ tms = tmf.getTrustManagers();
+ }
+ }
+
+ return tms;
+ }
+
+ /**
+ * Return the initialization parameters for the TrustManager.
+ * Currently, only the default <code>PKIX</code> is supported.
+ *
+ * @param algorithm The algorithm to get parameters for.
+ * @param crlf The path to the CRL file.
+ * @param trustStore The configured TrustStore.
+ * @return The parameters including the CRLs and TrustStore.
+ */
+ protected CertPathParameters getParameters(String algorithm,
+ String crlf,
+ KeyStore trustStore)
+ throws Exception {
+ CertPathParameters params = null;
+ if("PKIX".equalsIgnoreCase(algorithm)) {
+ PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore,
+ new
X509CertSelector());
+ Collection<? extends CRL> crls = getCRLs(crlf);
+ CertStoreParameters csp = new CollectionCertStoreParameters(crls);
+ CertStore store = CertStore.getInstance("Collection", csp);
+ xparams.addCertStore(store);
+ xparams.setRevocationEnabled(true);
+ xparams.setMaxPathLength(config.getSslTrustMaxCertLength());
+
+ params = xparams;
+ } else {
+ throw new CRLException("CRLs not supported for type: "+algorithm);
+ }
+ return params;
+ }
+
+
+ /**
+ * Load the collection of CRLs.
+ *
+ */
+ protected Collection<? extends CRL> getCRLs(String crlf)
+ throws IOException, CRLException, CertificateException {
+
+ File crlFile = new File(crlf);
+ if( !crlFile.isAbsolute() ) {
+ crlFile = new File(System.getProperty("catalina.base"), crlf);
+ }
+ Collection<? extends CRL> crls = null;
+ InputStream is = null;
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ is = new FileInputStream(crlFile);
+ crls = cf.generateCRLs(is);
+ } catch(IOException iex) {
+ throw iex;
+ } catch(CRLException crle) {
+ throw crle;
+ } catch(CertificateException ce) {
+ throw ce;
+ } finally {
+ if(is != null) {
+ try{
+ is.close();
+ } catch(Exception ex) {
+ }
+ }
+ }
+ return crls;
+ }
+
+ /**
+ * Set the SSL protocol variants to be enabled.
+ * @param socket the SSLServerSocket.
+ * @param protocols the protocols to use.
+ */
+ protected void setEnabledProtocols(SSLSocket socket, String []protocols){
+ if (protocols != null) {
+ socket.setEnabledProtocols(protocols);
+ }
+ }
+
+ /**
+ * Determines the SSL protocol variants to be enabled.
+ *
+ * @param socket The socket to get supported list from.
+ * @param requestedProtocols Comma-separated list of requested SSL
+ * protocol variants
+ *
+ * @return Array of SSL protocol variants to be enabled, or null if none of
+ * the requested protocol variants are supported
+ */
+ protected String[] getEnabledProtocols(SSLSocket socket,
+ String requestedProtocols){
+ String[] supportedProtocols = socket.getSupportedProtocols();
+
+ String[] enabledProtocols = null;
+
+ if (requestedProtocols != null) {
+ Vector<String> vec = null;
+ String protocol = requestedProtocols;
+ int index = requestedProtocols.indexOf(',');
+ if (index != -1) {
+ int fromIndex = 0;
+ while (index != -1) {
+ protocol = requestedProtocols.substring(fromIndex, index).trim();
+ if (protocol.length() > 0) {
+ /*
+ * Check to see if the requested protocol is among the
+ * supported protocols, i.e., may be enabled
+ */
+ for (int i=0; supportedProtocols != null
+ && i<supportedProtocols.length; i++) {
+ if (supportedProtocols[i].equals(protocol)) {
+ if (vec == null) {
+ vec = new Vector<String>();
+ }
+ vec.addElement(protocol);
+ break;
+ }
+ }
+ }
+ fromIndex = index+1;
+ index = requestedProtocols.indexOf(',', fromIndex);
+ } // while
+ protocol = requestedProtocols.substring(fromIndex);
+ }
+
+ if (protocol != null) {
+ protocol = protocol.trim();
+ if (protocol.length() > 0) {
+ /*
+ * Check to see if the requested protocol is among the
+ * supported protocols, i.e., may be enabled
+ */
+ for (int i=0; supportedProtocols != null
+ && i<supportedProtocols.length; i++) {
+ if (supportedProtocols[i].equals(protocol)) {
+ if (vec == null) {
+ vec = new Vector<String>();
+ }
+ vec.addElement(protocol);
+ break;
+ }
+ }
+ }
+ }
+
+ if (vec != null) {
+ enabledProtocols = new String[vec.size()];
+ vec.copyInto(enabledProtocols);
+ }
+ }
+
+ return enabledProtocols;
+ }
+
+ /**
+ * Configures the given SSL server socket with the requested cipher suites,
+ * protocol versions, and need for client authentication
+ */
+ private void initSocket(Socket ssocket) {
+
+ SSLSocket socket = (SSLSocket) ssocket;
+
+ if (enabledCiphers != null) {
+ socket.setEnabledCipherSuites(enabledCiphers);
+ }
+
+ setEnabledProtocols(socket, getEnabledProtocols(socket,
+ config.getSslProtocol()));
+
+ // we don't know if client auth is needed -
+ // after parsing the request we may re-handshake
+ //configureClientAuth(socket);
+ }
+
+}
Added: trunk/mod_cluster/src/main/resources/mod-cluster-jboss-beans.xml
===================================================================
--- trunk/mod_cluster/src/main/resources/mod-cluster-jboss-beans.xml
(rev 0)
+++ trunk/mod_cluster/src/main/resources/mod-cluster-jboss-beans.xml 2008-09-03 19:37:13
UTC (rev 1774)
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Beans that provide JBoss AS-side functionality for mod_cluster. These
+ beans are all "On Demand", i.e. that are not installed unless requested.
+-->
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- Configuration bean -->
+ <bean name="ModClusterConfig"
+
class="org.jboss.web.tomcat.service.modcluster.config.ModClusterConfig"
+ mode="On Demand">
+
+ <!-- Configure this node's communication with the load balancer -->
+
+ <!-- Comma separated list of address:port listing the httpd servers
+ where mod_cluster is running.
+ <property name="proxyList"></property>
+ -->
+ <!--URL prefix to send with commands to mod_cluster. Default is no prefix
+ <property name="proxyURL">/bla</property>
+ -->
+
+ <!-- mod_advertise is a small httpd module that advertises the
+ availability of httpd servers via multicast, allowing
+ ModClusterService to discover the httpd front-end instead of/in
+ addition to having them defined in proxyList.
+ -->
+ <!-- Whether to listen for advertise messages -->
+ <property name="advertise">true</property>
+ <!-- Multicast address to listen on for advertisements -->
+ <property
name="advertiseGroupAddress">${jboss.modcluster.advertise.address,jboss.partition.udpGroup:224.0.1.105}</property>
+ <!-- Port to listen to for advertisements -->
+ <property
name="advertisePort">${jboss.modcluster.advertise.address:23364}</property>
+
+ <!-- Key the front-end is going to send with advertise messages.
+ Default is no key no check.
+ <property name="advertiseSecurityKey"></property>
+ -->
+
+ <!-- Whether to use SSL to communicate with mod_cluster. Note this
+ has nothing to do with handling of https requests by JBoss Web -->
+ <property name="ssl">false</property>
+
+
+ <!-- Configuration values for the load balancer itself (must be the
+ same on all nodes in the cluster). These will be passed to the
+ load balancer. -->
+ <property name="stickySession">true</property>
+ <property name="stickySessionForce">false</property>
+ <property name="stickySessionRemove">false</property>
+ <property name="maxAttempts">-1</property>
+ <property name="workerTimeout">-1</property>
+
+ </bean>
+
+ <!-- Provides information to ModClusterService informing it how much load
+ this server should take. This basic impl just uses a static
+ configuration and doesn't adjust it based on runtime conditions. -->
+ <bean name="StaticModClusterLoadBalanceFactorProvider"
+
class="org.jboss.web.tomcat.service.modcluster.load.impl.StaticLoadBalanceFactorProvider"
+ mode="On Demand">
+ <property name="loadBalanceFactor">1</property>
+ </bean>
+
+ <bean name="DynamicModClusterLoadBalanceFactorProvider"
+
class="org.jboss.web.tomcat.service.modcluster.load.impl.DynamicLoadBalanceFactorProvider"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=LoadBalanceFactorProvider",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.impl.DynamicLoadBalanceFactorMBean.class)</annotation>
+ </bean>
+
+ <!-- Other metrics sources -->
+ <bean name="OperatingSystemLoadMetricSource"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.OperatingSystemLoadMetricSource"
+ mode="On Demand">
+ <constructor>
+ <parameter><inject
bean="ModClusterLoadBalanceFactorProvider"/></parameter>
+ </constructor>
+ </bean>
+
+ <!-- JBossWeb load metric sources -->
+ <bean name="RequestProcessorLoadMetricSource"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.RequestProcessorLoadMetricSource"
+ mode="On Demand">
+ <constructor>
+ <parameter><inject
bean="ModClusterLoadBalanceFactorProvider"/></parameter>
+ <parameter><inject bean="JMXKernel"
property="mbeanServer"/></parameter>
+ </constructor>
+ </bean>
+ <bean name="SessionLoadMetricSource"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.SessionLoadMetricSource"
+ mode="On Demand">
+ <constructor>
+ <parameter><inject
bean="ModClusterLoadBalanceFactorProvider"/></parameter>
+ <parameter><inject bean="JMXKernel"
property="mbeanServer"/></parameter>
+ </constructor>
+ </bean>
+ <bean name="ThreadPoolLoadMetricSource"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.ThreadPoolLoadMetricSource"
+ mode="On Demand">
+ <constructor>
+ <parameter><inject
bean="ModClusterLoadBalanceFactorProvider"/></parameter>
+ <parameter><inject bean="JMXKernel"
property="mbeanServer"/></parameter>
+ </constructor>
+ </bean>
+
+ <!-- System/JVM metrics -->
+ <bean name="AverageSystemLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.AverageSystemLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=AverageSystemLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="OperatingSystemLoadMetricSource"/></parameter>
+ </constructor>
+ </bean>
+ <bean name="SystemMemoryUsageLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.SystemMemoryUsageLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=SystemMemoryUsageLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="OperatingSystemLoadMetricSource"/></parameter>
+ </constructor>
+ </bean>
+ <bean name="HeapMemoryUsageLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.HeapMemoryUsageLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=HeapMemoryUsageLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="ModClusterLoadBalanceFactorProvider"/></parameter>
+ </constructor>
+ </bean>
+ <bean name="ThreadCountLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.ThreadCountLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=ThreadCountLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="ModClusterLoadBalanceFactorProvider"/></parameter>
+ </constructor>
+ <property name="capacity">300</property>
+ </bean>
+
+ <!-- Analogous to method=R in mod_jk -->
+ <bean name="RequestCountLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.RequestCountLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=RequestCountLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="RequestProcessorLoadMetricSource"/></parameter>
+ </constructor>
+ <property name="capacity">1000</property><!-- maximum
capacity estimated as 1000 requests/sec -->
+ </bean>
+
+ <!-- Analogous to method=S in mod_jk -->
+ <bean name="ActiveSessionsLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.ActiveSessionsLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=ActiveSessionsLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="SessionLoadMetricSource"/></parameter>
+ </constructor>
+ <property name="capacity">1000</property><!-- maximum
capacity estimated at 1000 sessions -->
+ </bean>
+
+ <!-- Analogous to method=T in mod_jk -->
+ <bean name="ReceiveTrafficLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.ReceiveTrafficLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=ReceiveTrafficLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="RequestProcessorLoadMetricSource"/></parameter>
+ </constructor>
+ <property name="capacity">1024</property><!-- maximum
capacity estimated at 1024KB/s -->
+ </bean>
+ <bean name="SendTrafficLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.SendTrafficLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=SendTrafficLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="RequestProcessorLoadMetricSource"/></parameter>
+ </constructor>
+ <property name="capacity">512</property><!-- maximum
capacity estimated at 512KB/s -->
+ </bean>
+
+ <!-- Analogous to method=B in mod_jk -->
+ <bean name="BusyConnectorsLoadMetric"
+
class="org.jboss.web.tomcat.service.modcluster.load.metric.impl.BusyConnectorsLoadMetric"
+ mode="On Demand">
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=BusyConnectorsLoadMetric",exposedInterface=org.jboss.web.tomcat.service.modcluster.load.metric.LoadMetricMBean.class)</annotation>
+ <constructor>
+ <parameter><inject
bean="ThreadPoolLoadMetricSource"/></parameter>
+ </constructor>
+ </bean>
+
+ <!-- The core ModClusterService -->
+ <bean name="ModClusterService"
+ class="org.jboss.web.tomcat.service.modcluster.ModClusterService"
+ mode="On Demand">
+
+
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=ModCluster",exposedInterface=org.jboss.web.tomcat.service.modcluster.ModClusterServiceMBean.class)</annotation>
+
+ <constructor>
+ <parameter><inject bean="HAPartition"/></parameter>
+ <parameter><inject
bean="ModClusterConfig"/></parameter>
+ <parameter><inject
bean="DynamicModClusterLoadBalanceFactorProvider"/></parameter>
+ <parameter><bean
class="org.jboss.ha.singleton.HASingletonElectionPolicySimple"/></parameter>
+ </constructor>
+
+ </bean>
+
+ <!--
+ An org.apache.catalina.LifecycleListener impl that notifies
+ ModClusterService of events inside JBoss Web (deployments, starts, stops. etc.)
+ -->
+ <bean name="ModClusterLifecycleListener"
+ class="org.jboss.web.tomcat.service.modcluster.BasicClusterListener"
+ mode="On Demand">
+
+ <constructor>
+ <parameter><inject
bean="ModClusterService"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
\ No newline at end of file
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/ha/ClusteredMCMPHandlerTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,767 @@
+/*
+ * 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.modcluster.ha;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.interfaces.HAPartition;
+import org.jboss.ha.framework.interfaces.HAServiceKeyProvider;
+import org.jboss.modcluster.config.MCMPHandlerConfiguration;
+import org.jboss.modcluster.ha.ClusteredMCMPHandler;
+import org.jboss.modcluster.ha.ClusteredMCMPHandlerImpl;
+import org.jboss.modcluster.ha.rpc.BooleanGroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.GroupRpcResponse;
+import org.jboss.modcluster.ha.rpc.GroupRpcResponseFilter;
+import org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
+import org.jboss.modcluster.ha.rpc.StringGroupRpcResponse;
+import org.jboss.modcluster.mcmp.AddressPort;
+import org.jboss.modcluster.mcmp.MCMPHandler;
+import org.jboss.modcluster.mcmp.MCMPRequest;
+import org.jboss.modcluster.mcmp.MCMPRequestType;
+import org.jboss.modcluster.mcmp.MCMPServer;
+import org.jboss.modcluster.mcmp.MCMPServerState;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class ClusteredMCMPHandlerTestCase extends TestCase
+{
+ private MCMPHandler localHandler = EasyMock.createStrictMock(MCMPHandler.class);
+ private HAServiceKeyProvider keyProvider =
EasyMock.createStrictMock(HAServiceKeyProvider.class);
+ private HAPartition partition = EasyMock.createStrictMock(HAPartition.class);
+
+ private ClusteredMCMPHandler handler = new ClusteredMCMPHandlerImpl(this.localHandler,
this.keyProvider);
+
+ public void testGetPartitionName()
+ {
+ String expected = "name";
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getPartitionName()).andReturn(expected);
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ String result = this.handler.getPartitionName();
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ assertSame(expected, result);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testInit() throws Exception
+ {
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+ InetAddress address = InetAddress.getLocalHost();
+ int port = 0;
+ String key = "key";
+
+ List<AddressPort> list = Collections.singletonList(new AddressPort(address,
port));
+
+ // Test master case
+ this.handler.setMasterNode(true);
+
+ this.localHandler.init(list);
+
+ EasyMock.replay(this.localHandler, this.keyProvider, this.partition);
+
+ this.handler.init(list);
+
+ EasyMock.verify(this.localHandler, this.keyProvider, this.partition);
+ EasyMock.reset(this.localHandler, this.keyProvider, this.partition);
+
+ // Test non-master case
+ this.handler.setMasterNode(false);
+
+ Capture<List<AddressPort>> capturedList = new
Capture<List<AddressPort>>();
+ Capture<Object[]> capturedEvents = new Capture<Object[]>();
+
+ this.localHandler.init(EasyMock.capture(capturedList));
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getClusterNode()).andReturn(node);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.eq(key),
EasyMock.eq("mcmpServerDiscoveryEvent"), EasyMock.capture(capturedEvents),
EasyMock.aryEq(new Class[] { MCMPServerDiscoveryEvent.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.localHandler, this.keyProvider, this.partition);
+
+ this.handler.init(list);
+
+ EasyMock.verify(this.localHandler, this.keyProvider, this.partition);
+
+ assertNotNull(capturedList.getValue());
+ assertTrue(capturedList.getValue().isEmpty());
+
+ List<MCMPServerDiscoveryEvent> events =
this.handler.getPendingDiscoveryEvents();
+
+ assertNotNull(events);
+ assertEquals(1, events.size());
+
+ MCMPServerDiscoveryEvent event = events.get(0);
+
+ assertSame(node, event.getSender());
+ assertSame(address, event.getMCMPServer().getAddress());
+ assertEquals(port, event.getMCMPServer().getPort());
+ assertTrue(event.isAddition());
+ assertEquals(1, event.getEventIndex());
+
+ assertNotNull(capturedEvents.getValue());
+ assertEquals(1, capturedEvents.getValue().length);
+ assertSame(event, capturedEvents.getValue()[0]);
+
+ EasyMock.reset(this.localHandler, this.keyProvider, this.partition);
+ }
+
+ public void testUpdateServersFromMasterNode() throws Exception
+ {
+ MCMPServer server = EasyMock.createMock(MCMPServer.class);
+ MCMPServerState state = EasyMock.createMock(MCMPServerState.class);
+ Set<MCMPServerState> states = Collections.emptySet();
+
+ InetAddress serverAddress = InetAddress.getLocalHost();
+ int serverPort = 0;
+ InetAddress stateAddress = InetAddress.getLocalHost();
+ int statePort = 1;
+
+ EasyMock.expect(server.getAddress()).andReturn(serverAddress);
+ EasyMock.expect(server.getPort()).andReturn(serverPort);
+ EasyMock.expect(server.isEstablished()).andReturn(true);
+
+ this.localHandler.addProxy(serverAddress, serverPort, true);
+
+
EasyMock.expect(this.localHandler.getProxyStates()).andReturn(Collections.singleton(state));
+
+ EasyMock.expect(state.getAddress()).andReturn(stateAddress);
+ EasyMock.expect(state.getPort()).andReturn(statePort);
+
+ this.localHandler.removeProxy(stateAddress, statePort);
+
+ this.localHandler.status();
+
+ EasyMock.expect(this.localHandler.getProxyStates()).andReturn(states);
+
+ EasyMock.replay(this.localHandler, server, state);
+
+ Set<MCMPServerState> result =
this.handler.updateServersFromMasterNode(Collections.singleton(server));
+
+ EasyMock.verify(this.localHandler, server, state);
+
+ assertSame(states, result);
+
+ EasyMock.reset(this.localHandler, server, state);
+ }
+
+ public void testGetConfiguration()
+ {
+ MCMPHandlerConfiguration configuration =
EasyMock.createMock(MCMPHandlerConfiguration.class);
+
+ EasyMock.expect(this.localHandler.getConfiguration()).andReturn(configuration);
+
+ EasyMock.replay(this.localHandler);
+
+ MCMPHandlerConfiguration result = this.handler.getConfiguration();
+
+ EasyMock.verify(this.localHandler);
+
+ assertSame(configuration, result);
+
+ EasyMock.reset(this.localHandler);
+ }
+
+ public void testAddProxy() throws Exception
+ {
+ InetAddress address = InetAddress.getLocalHost();
+ int port = 0;
+
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ // Test MCMPHandler.addProxy(String)
+ this.localHandler.addProxy(address, port);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.addProxy(address.getHostName() + ":" + port);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test MCMPHandler.addProxy(String, int)
+ this.localHandler.addProxy(address, port);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.addProxy(address.getHostName(), port);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test MCMPHandler.addProxy(InetAddress, int)
+ this.localHandler.addProxy(address, port);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.addProxy(address, port);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test MCMPHandler.addProxy(InetAddress, int, boolean)
+ this.localHandler.addProxy(address, port, true);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.addProxy(address, port, true);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ Capture<Object[]> capturedEvents = new Capture<Object[]>();
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+
+ // Test MCMPHandler.addProxy(String)
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getClusterNode()).andReturn(node);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.eq(key),
EasyMock.eq("mcmpServerDiscoveryEvent"), EasyMock.capture(capturedEvents),
EasyMock.aryEq(new Class[] { MCMPServerDiscoveryEvent.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.addProxy(address.getHostName() + ":" + port);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ List<MCMPServerDiscoveryEvent> events =
this.handler.getPendingDiscoveryEvents();
+
+ assertNotNull(events);
+ assertEquals(1, events.size());
+
+ MCMPServerDiscoveryEvent event = events.get(0);
+
+ assertSame(node, event.getSender());
+ assertSame(address, event.getMCMPServer().getAddress());
+ assertEquals(port, event.getMCMPServer().getPort());
+ assertTrue(event.isAddition());
+ assertEquals(1, event.getEventIndex());
+
+ assertNotNull(capturedEvents.getValue());
+ assertEquals(1, capturedEvents.getValue().length);
+ assertSame(event, capturedEvents.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+
+
+ // Test MCMPHandler.addProxy(String, int)
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getClusterNode()).andReturn(node);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.eq(key),
EasyMock.eq("mcmpServerDiscoveryEvent"), EasyMock.capture(capturedEvents),
EasyMock.aryEq(new Class[] { MCMPServerDiscoveryEvent.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.addProxy(address.getHostName(), port);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ events = this.handler.getPendingDiscoveryEvents();
+
+ assertNotNull(events);
+ assertEquals(2, events.size());
+
+ event = events.get(1);
+
+ assertSame(node, event.getSender());
+ assertSame(address, event.getMCMPServer().getAddress());
+ assertEquals(port, event.getMCMPServer().getPort());
+ assertTrue(event.isAddition());
+ assertEquals(2, event.getEventIndex());
+
+ assertNotNull(capturedEvents.getValue());
+ assertEquals(1, capturedEvents.getValue().length);
+ assertSame(event, capturedEvents.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+
+
+ // Test MCMPHandler.addProxy(InetAddress, int)
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getClusterNode()).andReturn(node);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.eq(key),
EasyMock.eq("mcmpServerDiscoveryEvent"), EasyMock.capture(capturedEvents),
EasyMock.aryEq(new Class[] { MCMPServerDiscoveryEvent.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.addProxy(address, port);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ events = this.handler.getPendingDiscoveryEvents();
+
+ assertNotNull(events);
+ assertEquals(3, events.size());
+
+ event = events.get(2);
+
+ assertSame(node, event.getSender());
+ assertSame(address, event.getMCMPServer().getAddress());
+ assertEquals(port, event.getMCMPServer().getPort());
+ assertTrue(event.isAddition());
+ assertEquals(3, event.getEventIndex());
+
+ assertNotNull(capturedEvents.getValue());
+ assertEquals(1, capturedEvents.getValue().length);
+ assertSame(event, capturedEvents.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+
+
+ // Test MCMPHandler.addProxy(InetAddress, int, boolean)
+ this.localHandler.addProxy(address, port, true);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.addProxy(address, port, true);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+ }
+
+ public void testRemoveProxy() throws Exception
+ {
+ InetAddress address = InetAddress.getLocalHost();
+ int port = 0;
+
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ // Test MCMPHandler.removeProxy(String, int)
+ this.localHandler.removeProxy(address, port);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.removeProxy(address.getHostName(), port);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test MCMPHandler.removeProxy(InetAddress, int)
+ this.localHandler.removeProxy(address, port);
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.removeProxy(address, port);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ Capture<Object[]> capturedEvents = new Capture<Object[]>();
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+
+ // Test MCMPHandler.removeProxy(String, int)
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getClusterNode()).andReturn(node);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.eq(key),
EasyMock.eq("mcmpServerDiscoveryEvent"), EasyMock.capture(capturedEvents),
EasyMock.aryEq(new Class[] { MCMPServerDiscoveryEvent.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.removeProxy(address.getHostName(), port);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ List<MCMPServerDiscoveryEvent> events =
this.handler.getPendingDiscoveryEvents();
+
+ assertNotNull(events);
+ assertEquals(1, events.size());
+
+ MCMPServerDiscoveryEvent event = events.get(0);
+
+ assertSame(node, event.getSender());
+ assertSame(address, event.getMCMPServer().getAddress());
+ assertEquals(port, event.getMCMPServer().getPort());
+ assertFalse(event.isAddition());
+ assertEquals(1, event.getEventIndex());
+
+ assertNotNull(capturedEvents.getValue());
+ assertEquals(1, capturedEvents.getValue().length);
+ assertSame(event, capturedEvents.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+
+
+ // Test MCMPHandler.removeProxy(InetAddress, int)
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.partition.getClusterNode()).andReturn(node);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.eq(key),
EasyMock.eq("mcmpServerDiscoveryEvent"), EasyMock.capture(capturedEvents),
EasyMock.aryEq(new Class[] { MCMPServerDiscoveryEvent.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.removeProxy(address, port);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ events = this.handler.getPendingDiscoveryEvents();
+
+ assertNotNull(events);
+ assertEquals(2, events.size());
+
+ event = events.get(1);
+
+ assertSame(node, event.getSender());
+ assertSame(address, event.getMCMPServer().getAddress());
+ assertEquals(port, event.getMCMPServer().getPort());
+ assertFalse(event.isAddition());
+ assertEquals(2, event.getEventIndex());
+
+ assertNotNull(capturedEvents.getValue());
+ assertEquals(1, capturedEvents.getValue().length);
+ assertSame(event, capturedEvents.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testGetProxyStates()
+ {
+ Set<MCMPServerState> states = Collections.emptySet();
+
+ EasyMock.expect(this.localHandler.getProxyStates()).andReturn(states);
+
+ EasyMock.replay(this.localHandler);
+
+ Set<MCMPServerState> result = this.handler.getProxyStates();
+
+ EasyMock.verify(this.localHandler);
+
+ assertSame(states, result);
+
+ EasyMock.reset(this.localHandler);
+ }
+
+ public void testGetLocalAddress() throws UnknownHostException, IOException
+ {
+ InetAddress address = InetAddress.getLocalHost();
+
+ EasyMock.expect(this.localHandler.getLocalAddress()).andReturn(address);
+
+ EasyMock.replay(this.localHandler);
+
+ InetAddress result = this.handler.getLocalAddress();
+
+ EasyMock.verify(this.localHandler);
+
+ assertSame(address, result);
+
+ EasyMock.reset(this.localHandler);
+ }
+
+ public void testGetProxyConfiguration() throws Exception
+ {
+ String configuration = "configuration";
+
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+
EasyMock.expect(this.localHandler.getProxyConfiguration()).andReturn(configuration);
+
+ EasyMock.replay(this.localHandler);
+
+ String result = this.handler.getProxyConfiguration();
+
+ EasyMock.verify(this.localHandler);
+
+ assertSame(configuration, result);
+
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.same(key),
EasyMock.eq("getProxyConfiguration"), EasyMock.aryEq(new Object[0]),
EasyMock.aryEq(new Class[0]), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new StringGroupRpcResponse(node,
configuration))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ result = this.handler.getProxyConfiguration();
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ assertSame(configuration, result);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testIsProxyHealthOK() throws Exception
+ {
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ EasyMock.expect(this.localHandler.isProxyHealthOK()).andReturn(true);
+
+ EasyMock.replay(this.localHandler);
+
+ boolean result = this.handler.isProxyHealthOK();
+
+ EasyMock.verify(this.localHandler);
+
+ assertTrue(result);
+
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.same(key),
EasyMock.eq("isProxyHealthOk"), EasyMock.aryEq(new Object[0]),
EasyMock.aryEq(new Class[0]), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new BooleanGroupRpcResponse(node,
true))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ result = this.handler.isProxyHealthOK();
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ assertTrue(result);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testMarkProxiesInError() throws Exception
+ {
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ this.localHandler.markProxiesInError();
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.markProxiesInError();
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.same(key),
EasyMock.eq("markProxiesInError"), EasyMock.aryEq(new Object[0]),
EasyMock.aryEq(new Class[0]), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new BooleanGroupRpcResponse(node,
true))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.markProxiesInError();
+
+ EasyMock.verify(this.keyProvider, this.partition);
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testReset() throws Exception
+ {
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ this.localHandler.reset();
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.reset();
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.same(key),
EasyMock.eq("reset"), EasyMock.aryEq(new Object[0]), EasyMock.aryEq(new
Class[0]), EasyMock.eq(false), EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new BooleanGroupRpcResponse(node,
true))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.reset();
+
+ EasyMock.verify(this.keyProvider, this.partition);
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testSendRequest() throws Exception
+ {
+ MCMPRequest request = new MCMPRequest(MCMPRequestType.INFO, false,
Collections.singletonMap("name", "value"));
+
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ this.localHandler.sendRequest(EasyMock.same(request));
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.sendRequest(request);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+ Capture<Object[]> captured = new Capture<Object[]>();
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.same(key),
EasyMock.eq("sendRequest"), EasyMock.capture(captured), EasyMock.aryEq(new
Class[] { MCMPRequest.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.sendRequest(request);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ assertNotNull(captured.getValue());
+ assertEquals(1, captured.getValue().length);
+ assertSame(request, captured.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testSendRequests() throws Exception
+ {
+ List<MCMPRequest> requests = Collections.emptyList();
+
+ // Test master use case
+ this.handler.setMasterNode(true);
+
+ this.localHandler.sendRequests(EasyMock.same(requests));
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.sendRequests(requests);
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+
+
+ // Test non-master use case
+ this.handler.setMasterNode(false);
+
+ String key = "key";
+ ClusterNode node = EasyMock.createMock(ClusterNode.class);
+ Capture<Object[]> captured = new Capture<Object[]>();
+
+ EasyMock.expect(this.keyProvider.getHAPartition()).andReturn(this.partition);
+ EasyMock.expect(this.keyProvider.getHAServiceKey()).andReturn(key);
+
+ EasyMock.expect(this.partition.callMethodOnCluster(EasyMock.same(key),
EasyMock.eq("sendRequests"), EasyMock.capture(captured), EasyMock.aryEq(new
Class[] { List.class }), EasyMock.eq(false),
EasyMock.isA(GroupRpcResponseFilter.class))).andReturn(new
ArrayList<GroupRpcResponse>(Collections.singleton(new GroupRpcResponse(node))));
+
+ EasyMock.replay(this.keyProvider, this.partition);
+
+ this.handler.sendRequests(requests);
+
+ EasyMock.verify(this.keyProvider, this.partition);
+
+ assertNotNull(captured.getValue());
+ assertEquals(1, captured.getValue().length);
+ assertSame(requests, captured.getValue()[0]);
+
+ EasyMock.reset(this.keyProvider, this.partition);
+ }
+
+ public void testShutdown()
+ {
+ this.localHandler.shutdown();
+
+ EasyMock.replay(this.localHandler);
+
+ this.handler.shutdown();
+
+ EasyMock.verify(this.localHandler);
+ EasyMock.reset(this.localHandler);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/DynamicLoadBalanceFactorProviderTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/DynamicLoadBalanceFactorProviderTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/DynamicLoadBalanceFactorProviderTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,158 @@
+/*
+ * 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.modcluster.load;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.impl.DynamicLoadBalanceFactorProvider;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class DynamicLoadBalanceFactorProviderTestCase extends TestCase
+{
+ private final LoadMetricSource source1 =
EasyMock.createStrictMock(LoadMetricSource.class);
+ private final LoadMetricSource source2 =
EasyMock.createStrictMock(LoadMetricSource.class);
+ private final LoadMetric metric1 = EasyMock.createStrictMock(LoadMetric.class);
+ private final LoadMetric metric2 = EasyMock.createStrictMock(LoadMetric.class);
+ private final LoadMetric metric3 = EasyMock.createStrictMock(LoadMetric.class);
+
+ private final DynamicLoadBalanceFactorProvider provider = new
DynamicLoadBalanceFactorProvider();
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ this.provider.add(this.source1);
+ this.provider.add(this.source2);
+ this.provider.setHistory(2);
+ }
+
+
+ public void testGetLoadBalanceFactor() throws Exception
+ {
+ EasyMock.expect(this.source1.getMetrics()).andReturn(Arrays.asList(this.metric1,
this.metric2));
+
+ EasyMock.expect(this.metric1.getWeight()).andReturn(1);
+ EasyMock.expect(this.metric2.getWeight()).andReturn(2);
+
+ this.source1.prepare();
+
+ EasyMock.expect(this.metric1.getLoad()).andReturn(0.2);
+ EasyMock.expect(this.metric1.getCapacity()).andReturn(1d);
+ EasyMock.expect(this.metric1.getWeight()).andReturn(1);
+
+ EasyMock.expect(this.metric2.getLoad()).andReturn(400d);
+ EasyMock.expect(this.metric2.getCapacity()).andReturn(1000d);
+ EasyMock.expect(this.metric2.getWeight()).andReturn(2);
+
+ this.source1.cleanup();
+
+
EasyMock.expect(this.source2.getMetrics()).andReturn(Collections.singleton(this.metric3));
+
+ EasyMock.expect(this.metric3.getWeight()).andReturn(0);
+
+ EasyMock.replay(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ int loadBalanceFactor = this.provider.getLoadBalanceFactor();
+
+ EasyMock.verify(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ assertEquals(67, loadBalanceFactor);
+
+ EasyMock.reset(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ // Test time-decay function
+ EasyMock.expect(this.source1.getMetrics()).andReturn(Arrays.asList(this.metric1,
this.metric2));
+
+ EasyMock.expect(this.metric1.getWeight()).andReturn(1);
+ EasyMock.expect(this.metric2.getWeight()).andReturn(2);
+
+ this.source1.prepare();
+
+ EasyMock.expect(this.metric1.getLoad()).andReturn(0.4);
+ EasyMock.expect(this.metric1.getCapacity()).andReturn(1d);
+ EasyMock.expect(this.metric1.getWeight()).andReturn(1);
+
+ EasyMock.expect(this.metric2.getLoad()).andReturn(600d);
+ EasyMock.expect(this.metric2.getCapacity()).andReturn(1000d);
+ EasyMock.expect(this.metric2.getWeight()).andReturn(2);
+
+ this.source1.cleanup();
+
+
EasyMock.expect(this.source2.getMetrics()).andReturn(Collections.singleton(this.metric3));
+
+ EasyMock.expect(this.metric3.getWeight()).andReturn(0);
+
+ EasyMock.replay(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ loadBalanceFactor = this.provider.getLoadBalanceFactor();
+
+ EasyMock.verify(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ assertEquals(53, loadBalanceFactor);
+
+ EasyMock.reset(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ //Test decay queue overflow
+ EasyMock.expect(this.source1.getMetrics()).andReturn(Arrays.asList(this.metric1,
this.metric2));
+
+ EasyMock.expect(this.metric1.getWeight()).andReturn(1);
+ EasyMock.expect(this.metric2.getWeight()).andReturn(2);
+
+ this.source1.prepare();
+
+ EasyMock.expect(this.metric1.getLoad()).andReturn(0.3);
+ EasyMock.expect(this.metric1.getCapacity()).andReturn(1d);
+ EasyMock.expect(this.metric1.getWeight()).andReturn(1);
+
+ EasyMock.expect(this.metric2.getLoad()).andReturn(300d);
+ EasyMock.expect(this.metric2.getCapacity()).andReturn(1000d);
+ EasyMock.expect(this.metric2.getWeight()).andReturn(2);
+
+ this.source1.cleanup();
+
+
EasyMock.expect(this.source2.getMetrics()).andReturn(Collections.singleton(this.metric3));
+
+ EasyMock.expect(this.metric3.getWeight()).andReturn(0);
+
+ EasyMock.replay(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ loadBalanceFactor = this.provider.getLoadBalanceFactor();
+
+ EasyMock.verify(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+
+ assertEquals(62, loadBalanceFactor);
+
+ EasyMock.reset(this.source1, this.source2, this.metric1, this.metric2,
this.metric3);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/StaticLoadBalanceFactorProviderTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/StaticLoadBalanceFactorProviderTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/StaticLoadBalanceFactorProviderTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,48 @@
+/*
+ * 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.modcluster.load;
+
+import org.jboss.modcluster.load.impl.StaticLoadBalanceFactorProvider;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class StaticLoadBalanceFactorProviderTestCase extends TestCase
+{
+ private StaticLoadBalanceFactorProvider provider = new
StaticLoadBalanceFactorProvider();
+
+ public void testGetLoadBalanceFactor()
+ {
+ int factor = this.provider.getLoadBalanceFactor();
+
+ assertEquals(1, factor);
+
+ this.provider.setLoadBalanceFactor(3);
+
+ factor = this.provider.getLoadBalanceFactor();
+
+ assertEquals(3, factor);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ActiveSessionsLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ActiveSessionsLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ActiveSessionsLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,133 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.ActiveSessionsLoadMetric;
+import org.jboss.modcluster.load.metric.impl.SessionLoadMetricSource;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class ActiveSessionsLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ SessionLoadMetricSource source = new SessionLoadMetricSource(registration,
this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+ this.metric = new ActiveSessionsLoadMetric(source);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName pattern = ObjectName.getInstance("jboss.web:type=Manager,*");
+ ObjectName name1 =
ObjectName.getInstance("jboss.web:type=Manager,path=/app1,host=localhost");
+ ObjectName name2 =
ObjectName.getInstance("jboss.web:type=Manager,path=/app2,host=localhost");
+
+ Comparator<ObjectName> comparator = new Comparator<ObjectName>()
+ {
+ public int compare(ObjectName name1, ObjectName name2)
+ {
+ return name1.getCanonicalName().compareTo(name2.getCanonicalName());
+ }
+ };
+
+ Set<ObjectName> names = new TreeSet<ObjectName>(comparator);
+ names.addAll(Arrays.asList(name1, name2));
+
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"LocalActiveSessions")).andReturn(1);
+ EasyMock.expect(this.server.getAttribute(name2,
"LocalActiveSessions")).andReturn(2);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(3.0, load);
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/AverageSystemLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/AverageSystemLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/AverageSystemLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,151 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.util.Collection;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.AverageSystemLoadMetric;
+import org.jboss.modcluster.load.metric.impl.OperatingSystemLoadMetricSource;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class AverageSystemLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ OperatingSystemLoadMetricSource source = new
OperatingSystemLoadMetricSource(registration, this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+
+ ObjectName name =
ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+
+ // Test Java 1.5 case
+ MBeanInfo info = new MBeanInfo(OperatingSystemMXBean.class.getName(), null, null,
null, null, null);
+
+ EasyMock.expect(this.server.getMBeanInfo(name)).andReturn(info);
+
+ EasyMock.replay(this.server);
+
+ this.metric = new AverageSystemLoadMetric(source);
+
+ EasyMock.verify(this.server);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertTrue(metrics.isEmpty());
+
+ EasyMock.reset(this.server);
+
+ // Test Java 1.6 case
+ MBeanAttributeInfo attribute = new
MBeanAttributeInfo("SystemLoadAverage", Double.TYPE.getName(), null, true,
false, false);
+
+ info = new MBeanInfo(OperatingSystemMXBean.class.getName(), "", new
MBeanAttributeInfo[] { attribute }, null, null, null);
+
+ EasyMock.expect(this.server.getMBeanInfo(name)).andReturn(info);
+
+ EasyMock.replay(this.server);
+
+ this.metric = new AverageSystemLoadMetric(source);
+
+ EasyMock.verify(this.server);
+
+ metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+
+ EasyMock.reset(this.server);
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName name =
ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name,
"SystemLoadAverage")).andReturn(0.1);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(0.1, load);
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/BusyConnectorsLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/BusyConnectorsLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/BusyConnectorsLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,136 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.BusyConnectorsLoadMetric;
+import org.jboss.modcluster.load.metric.impl.ThreadPoolLoadMetricSource;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class BusyConnectorsLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ ThreadPoolLoadMetricSource source = new ThreadPoolLoadMetricSource(registration,
this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+ this.metric = new BusyConnectorsLoadMetric(source);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertEquals(this.metric, metrics.iterator().next());
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName pattern =
ObjectName.getInstance("jboss.web:type=ThreadPool,*");
+ ObjectName name1 =
ObjectName.getInstance("jboss.web:type=ThreadPool,name=http-8080");
+ ObjectName name2 =
ObjectName.getInstance("jboss.web:type=ThreadPool,name=jk-8009");
+
+ Comparator<ObjectName> comparator = new Comparator<ObjectName>()
+ {
+ public int compare(ObjectName name1, ObjectName name2)
+ {
+ return name1.getCanonicalName().compareTo(name2.getCanonicalName());
+ }
+ };
+
+ Set<ObjectName> names = new TreeSet<ObjectName>(comparator);
+ names.addAll(Arrays.asList(name1, name2));
+
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"currentThreadsBusy")).andReturn(1);
+ EasyMock.expect(this.server.getAttribute(name2,
"currentThreadsBusy")).andReturn(2);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"maxThreads")).andReturn(2);
+ EasyMock.expect(this.server.getAttribute(name2,
"maxThreads")).andReturn(2);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(0.75, load);
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ConnectionPoolUsageLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ConnectionPoolUsageLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ConnectionPoolUsageLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,136 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.ConnectionPoolLoadMetricSource;
+import org.jboss.modcluster.load.metric.impl.ConnectionPoolUsageLoadMetric;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class ConnectionPoolUsageLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ ConnectionPoolLoadMetricSource source = new
ConnectionPoolLoadMetricSource(registration, this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+ this.metric = new ConnectionPoolUsageLoadMetric(source);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertEquals(this.metric, metrics.iterator().next());
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName pattern =
ObjectName.getInstance("jboss.jca:service=ManagedConnectionPool,*");
+ ObjectName name1 =
ObjectName.getInstance("jboss.jca:service=ManagedConnectionPool,name=DS1");
+ ObjectName name2 =
ObjectName.getInstance("jboss.jca:service=ManagedConnectionPool,name=DS2");
+
+ Comparator<ObjectName> comparator = new Comparator<ObjectName>()
+ {
+ public int compare(ObjectName name1, ObjectName name2)
+ {
+ return name1.getCanonicalName().compareTo(name2.getCanonicalName());
+ }
+ };
+
+ Set<ObjectName> names = new TreeSet<ObjectName>(comparator);
+ names.addAll(Arrays.asList(name1, name2));
+
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"InUseConnectionCount")).andReturn(10);
+ EasyMock.expect(this.server.getAttribute(name2,
"InUseConnectionCount")).andReturn(20);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"MaxSize")).andReturn(20);
+ EasyMock.expect(this.server.getAttribute(name2,
"MaxSize")).andReturn(20);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(0.75, load);
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/HeapMemoryUsageLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/HeapMemoryUsageLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/HeapMemoryUsageLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,111 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.HeapMemoryUsageLoadMetric;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class HeapMemoryUsageLoadMetricTestCase extends TestCase
+{
+ private final MemoryMXBean bean = EasyMock.createStrictMock(MemoryMXBean.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.bean);
+
+ HeapMemoryUsageLoadMetric source = new HeapMemoryUsageLoadMetric(registration,
this.bean);
+
+ EasyMock.verify(registration, this.bean);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.bean);
+
+ this.source = source;
+ this.metric = source;
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ EasyMock.replay(this.bean);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.bean);
+ EasyMock.reset(this.bean);
+
+ MemoryUsage usage = new MemoryUsage(0, 1000, 2000, 5000);
+
+ EasyMock.expect(this.bean.getHeapMemoryUsage()).andReturn(usage);
+
+ EasyMock.replay(this.bean);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.bean);
+
+ assertEquals(0.2, load);
+
+ EasyMock.reset(this.bean);
+
+ EasyMock.replay(this.bean);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.bean);
+ EasyMock.reset(this.bean);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ReceiveTrafficLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ReceiveTrafficLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ReceiveTrafficLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,167 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.ReceiveTrafficLoadMetric;
+import org.jboss.modcluster.load.metric.impl.RequestProcessorLoadMetricSource;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class ReceiveTrafficLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ RequestProcessorLoadMetricSource source = new
RequestProcessorLoadMetricSource(registration, this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+ this.metric = new ReceiveTrafficLoadMetric(source);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+
+ // Sleep for a sec to prevent infinite load
+ Thread.sleep(500);
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName pattern =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,*");
+ ObjectName name1 =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,name=http-8080");
+ ObjectName name2 =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,name=jk-8009");
+
+ Comparator<ObjectName> comparator = new Comparator<ObjectName>()
+ {
+ public int compare(ObjectName name1, ObjectName name2)
+ {
+ return name1.getCanonicalName().compareTo(name2.getCanonicalName());
+ }
+ };
+
+ Set<ObjectName> names = new TreeSet<ObjectName>(comparator);
+ names.addAll(Arrays.asList(name1, name2));
+
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"bytesReceived")).andReturn(1000L);
+ EasyMock.expect(this.server.getAttribute(name2,
"bytesReceived")).andReturn(2000L);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(6, Math.round(load));
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ Thread.sleep(500);
+ // Test incremental load
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"bytesReceived")).andReturn(2000L);
+ EasyMock.expect(this.server.getAttribute(name2,
"bytesReceived")).andReturn(3000L);
+
+ EasyMock.replay(this.server);
+
+ load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(4, Math.round(load));
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/RequestCountLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/RequestCountLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/RequestCountLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,168 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.RequestCountLoadMetric;
+import org.jboss.modcluster.load.metric.impl.RequestProcessorLoadMetricSource;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class RequestCountLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ RequestProcessorLoadMetricSource source = new
RequestProcessorLoadMetricSource(registration, this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+ this.metric = new RequestCountLoadMetric(source);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+
+ // Sleep for a sec to avoid infinite load.
+ Thread.sleep(500);
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName pattern =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,*");
+ ObjectName name1 =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,name=http-8080");
+ ObjectName name2 =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,name=jk-8009");
+
+ Comparator<ObjectName> comparator = new Comparator<ObjectName>()
+ {
+ public int compare(ObjectName name1, ObjectName name2)
+ {
+ return name1.getCanonicalName().compareTo(name2.getCanonicalName());
+ }
+ };
+
+ Set<ObjectName> names = new TreeSet<ObjectName>(comparator);
+ names.addAll(Arrays.asList(name1, name2));
+
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"requestCount")).andReturn(1);
+ EasyMock.expect(this.server.getAttribute(name2,
"requestCount")).andReturn(2);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(6, Math.round(load));
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ Thread.sleep(500);
+
+ // Test incremental load
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"requestCount")).andReturn(2);
+ EasyMock.expect(this.server.getAttribute(name2,
"requestCount")).andReturn(3);
+
+ EasyMock.replay(this.server);
+
+ load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(4, Math.round(load));
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SendTrafficLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SendTrafficLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SendTrafficLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,168 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.RequestProcessorLoadMetricSource;
+import org.jboss.modcluster.load.metric.impl.SendTrafficLoadMetric;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class SendTrafficLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ RequestProcessorLoadMetricSource source = new
RequestProcessorLoadMetricSource(registration, this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+ this.metric = new SendTrafficLoadMetric(source);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+
+ // Sleep for a bit to avoid infinite load
+ Thread.sleep(500);
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName pattern =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,*");
+ ObjectName name1 =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,name=http-8080");
+ ObjectName name2 =
ObjectName.getInstance("jboss.web:type=GlobalRequestProcessor,name=jk-8009");
+
+ Comparator<ObjectName> comparator = new Comparator<ObjectName>()
+ {
+ public int compare(ObjectName name1, ObjectName name2)
+ {
+ return name1.getCanonicalName().compareTo(name2.getCanonicalName());
+ }
+ };
+
+ Set<ObjectName> names = new TreeSet<ObjectName>(comparator);
+ names.addAll(Arrays.asList(name1, name2));
+
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"bytesSent")).andReturn(1000L);
+ EasyMock.expect(this.server.getAttribute(name2,
"bytesSent")).andReturn(2000L);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(6, Math.round(load));
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ Thread.sleep(500);
+
+ // Test incremental load
+ EasyMock.expect(this.server.queryNames(pattern, null)).andReturn(names);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name1,
"bytesSent")).andReturn(2000L);
+ EasyMock.expect(this.server.getAttribute(name2,
"bytesSent")).andReturn(3000L);
+
+ EasyMock.replay(this.server);
+
+ load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(4, Math.round(load));
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SystemMemoryUsageLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SystemMemoryUsageLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/SystemMemoryUsageLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,155 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.lang.management.ManagementFactory;
+import java.util.Collection;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.AverageSystemLoadMetric;
+import org.jboss.modcluster.load.metric.impl.OperatingSystemLoadMetricSource;
+import org.jboss.modcluster.load.metric.impl.SystemMemoryUsageLoadMetric;
+
+import com.sun.management.OperatingSystemMXBean;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class SystemMemoryUsageLoadMetricTestCase extends TestCase
+{
+ private final MBeanServer server = EasyMock.createStrictMock(MBeanServer.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.server);
+
+ OperatingSystemLoadMetricSource source = new
OperatingSystemLoadMetricSource(registration, this.server);
+
+ EasyMock.verify(registration, this.server);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.server);
+
+ this.source = source;
+
+ ObjectName name =
ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+
+ // Test non-com.sun.management.OperatingSystemMXBean case
+ MBeanInfo info = new MBeanInfo(OperatingSystemMXBean.class.getName(), null, null,
null, null, null);
+
+ EasyMock.expect(this.server.getMBeanInfo(name)).andReturn(info);
+
+ EasyMock.replay(this.server);
+
+ this.metric = new AverageSystemLoadMetric(source);
+
+ EasyMock.verify(this.server);
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertTrue(metrics.isEmpty());
+
+ EasyMock.reset(this.server);
+
+ // Test com.sun.management.OperatingSystemMXBean case
+ MBeanAttributeInfo attribute1 = new
MBeanAttributeInfo("FreePhysicalMemorySize", Long.TYPE.getName(), null, true,
false, false);
+ MBeanAttributeInfo attribute2 = new
MBeanAttributeInfo("TotalPhysicalMemorySize", Long.TYPE.getName(), null, true,
false, false);
+
+ info = new MBeanInfo(OperatingSystemMXBean.class.getName(), "", new
MBeanAttributeInfo[] { attribute1, attribute2 }, null, null, null);
+
+ EasyMock.expect(this.server.getMBeanInfo(name)).andReturn(info);
+
+ EasyMock.replay(this.server);
+
+ this.metric = new SystemMemoryUsageLoadMetric(source);
+
+ EasyMock.verify(this.server);
+
+ metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+
+ EasyMock.reset(this.server);
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ ObjectName name =
ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+
+ EasyMock.replay(this.server);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+
+ EasyMock.expect(this.server.getAttribute(name,
"FreePhysicalMemorySize")).andReturn(1000L);
+ EasyMock.expect(this.server.getAttribute(name,
"TotalPhysicalMemorySize")).andReturn(5000L);
+
+ EasyMock.replay(this.server);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.server);
+
+ assertEquals(0.2, load);
+
+ EasyMock.reset(this.server);
+
+ EasyMock.replay(this.server);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.server);
+ EasyMock.reset(this.server);
+ }
+}
Added:
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ThreadCountLoadMetricTestCase.java
===================================================================
---
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ThreadCountLoadMetricTestCase.java
(rev 0)
+++
trunk/mod_cluster/src/test/java/org/jboss/modcluster/load/metric/ThreadCountLoadMetricTestCase.java 2008-09-03
19:37:13 UTC (rev 1774)
@@ -0,0 +1,108 @@
+/*
+ * 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.modcluster.load.metric;
+
+import java.lang.management.ThreadMXBean;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jboss.modcluster.load.metric.LoadMetric;
+import org.jboss.modcluster.load.metric.LoadMetricSource;
+import org.jboss.modcluster.load.metric.LoadMetricSourceRegistration;
+import org.jboss.modcluster.load.metric.impl.ThreadCountLoadMetric;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public class ThreadCountLoadMetricTestCase extends TestCase
+{
+ private final ThreadMXBean bean = EasyMock.createStrictMock(ThreadMXBean.class);
+
+ private LoadMetricSource source;
+ private LoadMetric metric;
+
+ /**
+ * @{inheritDoc}
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ LoadMetricSourceRegistration registration =
EasyMock.createStrictMock(LoadMetricSourceRegistration.class);
+
+ Capture<LoadMetricSource> captured = new Capture<LoadMetricSource>();
+
+ registration.add(EasyMock.capture(captured));
+
+ EasyMock.replay(registration, this.bean);
+
+ ThreadCountLoadMetric source = new ThreadCountLoadMetric(registration, this.bean);
+
+ EasyMock.verify(registration, this.bean);
+
+ assertSame(source, captured.getValue());
+
+ EasyMock.reset(registration, this.bean);
+
+ this.source = source;
+ this.metric = source;
+
+ Collection<? extends LoadMetric> metrics = this.source.getMetrics();
+
+ assertNotNull(metrics);
+ assertEquals(1, metrics.size());
+ assertSame(this.metric, metrics.iterator().next());
+ }
+
+ public void testGetLoad() throws Exception
+ {
+ EasyMock.replay(this.bean);
+
+ this.source.prepare();
+
+ EasyMock.verify(this.bean);
+ EasyMock.reset(this.bean);
+
+ EasyMock.expect(this.bean.getThreadCount()).andReturn(50);
+
+ EasyMock.replay(this.bean);
+
+ double load = this.metric.getLoad();
+
+ EasyMock.verify(this.bean);
+
+ assertEquals(50.0, load);
+
+ EasyMock.reset(this.bean);
+
+ EasyMock.replay(this.bean);
+
+ this.source.cleanup();
+
+ EasyMock.verify(this.bean);
+ EasyMock.reset(this.bean);
+ }
+}