mirror of https://github.com/apache/activemq.git
Moved the trunk code into the trunk sub directory
git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@356304 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
commit
40a7d3b6ac
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Protique Ltd
|
||||
* Copyright 2004 Hiram Chirino
|
||||
* Copyright 2005 (C) LogicBlaze, Inc. http://www.logicblaze.com
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
**/
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
Welcome to ActiveMQ
|
||||
===================
|
||||
|
||||
ActiveMQ is a high performance Apache 2.0 licenced Message Broker and JMS 1.1 implementation.
|
||||
|
||||
To help you get started, try the following links:-
|
||||
|
||||
Getting Started
|
||||
http://activemq.org/Getting+Started
|
||||
|
||||
Building
|
||||
http://activemq.org/Building
|
||||
|
||||
Examples
|
||||
http://activemq.org/Examples
|
||||
|
||||
We welcome contributions of all kinds, for details of how you can help
|
||||
http://activemq.codehaus.org/Contributing
|
||||
|
||||
Please refer to the website for details of finding the issue tracker, email lists, wiki or IRC channel
|
||||
http://activemq.org/
|
||||
|
||||
|
||||
Please help us make ActiveMQ better - we appreciate any feedback you may have.
|
||||
|
||||
Enjoy!
|
||||
|
||||
-----------------
|
||||
The ActiveMQ team
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/java"/>
|
||||
<classpathentry output="target/test-classes" kind="src" path="src/test"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/junit/jars/junit-3.8.1.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/commons-logging/jars/commons-logging-1.0.3.jar"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/concurrent/jars/concurrent-1.3.2.jar"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/geronimo-spec/jars/geronimo-spec-jms-1.1-rc1.jar"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/geronimo-spec/jars/geronimo-spec-jta-1.0.1B-rc1.jar"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/geronimo-spec/jars/geronimo-spec-j2ee-management-1.0-rc1.jar"/>
|
||||
<classpathentry kind="var" path="MAVEN_REPO/jdbm/jars/jdbm-0.12.jar"/>
|
||||
<classpathentry kind="src" path="/activemq"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
|
@ -0,0 +1,10 @@
|
|||
target
|
||||
bin
|
||||
*.log
|
||||
junit*.properties
|
||||
activecluster.iml
|
||||
activecluster.ipr
|
||||
activecluster.iws
|
||||
ActiveMQ
|
||||
classes
|
||||
test-classes
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<projectDescription>
|
||||
<name>activecluster</name>
|
||||
<comment>ActiveCluster is a framework for building cluster-aware software</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>
|
|
@ -0,0 +1,23 @@
|
|||
Welcome to ActiveCluster!
|
||||
=========================
|
||||
|
||||
ActiveCluster is an Apache 2.0 licenced cluster communication toolkit.
|
||||
|
||||
To help you get started, try surfing the following links...
|
||||
|
||||
Building
|
||||
http://activecluster.codehaus.org/Building
|
||||
|
||||
Examples
|
||||
http://activecluster.codehaus.org/Examples
|
||||
|
||||
Refer to the website for details of finding the issue tracker, email lists, wiki or IRC channel
|
||||
http://activecluster.codehaus.org/
|
||||
|
||||
Please help us make ActiveCluster better - we appreciate any feedback you may have.
|
||||
|
||||
Enjoy!
|
||||
|
||||
|
||||
----------------------
|
||||
The ActiveCluster team
|
|
@ -0,0 +1,63 @@
|
|||
<project default="default" xmlns:j="jelly:core">
|
||||
|
||||
<goal name="default" prereqs="clean, test"/>
|
||||
|
||||
<goal name="dc">
|
||||
<attain>
|
||||
<attainGoal name="clean"/>
|
||||
<attainGoal name="site:deploy"/>
|
||||
<j:set var="maven.test.skip" value="true"/>
|
||||
<attainGoal name="jar:deploy"/>
|
||||
<attainGoal name="dist:deploy"/>
|
||||
</attain>
|
||||
</goal>
|
||||
|
||||
<preGoal name="site:deploy">
|
||||
<attainGoal name="javadoc"/>
|
||||
<attainGoal name="java:compile"/>
|
||||
<attainGoal name="clover"/>
|
||||
</preGoal>
|
||||
|
||||
<goal name="setclasspath" prereqs="java:compile, test:compile">
|
||||
<path id="test.classpath">
|
||||
<pathelement path="${maven.build.dest}"/>
|
||||
<pathelement path="target/classes"/>
|
||||
<pathelement path="target/test-classes"/>
|
||||
<path refid="maven.dependency.classpath"/>
|
||||
</path>
|
||||
</goal>
|
||||
|
||||
<!-- Sample programs -->
|
||||
<goal name="demo:A" prereqs="setclasspath"
|
||||
description="Runs the simple ActiveCluster Demo">
|
||||
<echo>Running the ActiveCluster demo...</echo>
|
||||
<java classname="org.activecluster.ClusterDemo" fork="true">
|
||||
<classpath refid="test.classpath"/>
|
||||
<sysproperty key="org.apache.commons.logging.simplelog.defaultlog" value="debug"/>
|
||||
<arg value="A"/>
|
||||
</java>
|
||||
</goal>
|
||||
|
||||
<goal name="demo:B" prereqs="setclasspath"
|
||||
description="Runs the simple ActiveCluster Demo">
|
||||
<echo>Running the ActiveCluster demo...</echo>
|
||||
<java classname="org.activecluster.ClusterDemo" fork="true">
|
||||
<classpath refid="test.classpath"/>
|
||||
<arg value="B"/>
|
||||
</java>
|
||||
</goal>
|
||||
|
||||
|
||||
<!--
|
||||
Uses keyboard input so can't be run in Maven
|
||||
|
||||
<goal name="chat" prereqs="setclasspath"
|
||||
description="Runs the ActiveCluster Chat Demo">
|
||||
<echo>Running the ActiveCluster Chat demo...</echo>
|
||||
<java classname="org.activecluster.ChatDemo" fork="true">
|
||||
<classpath refid="test.classpath"/>
|
||||
</java>
|
||||
</goal>
|
||||
-->
|
||||
|
||||
</project>
|
|
@ -0,0 +1,40 @@
|
|||
maven.repo.remote=http://www.ibiblio.org/maven,http://dist.codehaus.org,http://cvs.apache.org/repository
|
||||
|
||||
maven.compile.source=1.4
|
||||
maven.compile.target=1.4
|
||||
maven.test.source=1.4
|
||||
maven.compile.deprecation=true
|
||||
maven.compile.debug=true
|
||||
maven.compile.optimize=true
|
||||
|
||||
maven.javadoc.links=http://java.sun.com/j2se/1.4.1/docs/api/,http://java.sun.com/j2ee/1.4/docs/api/
|
||||
maven.javadoc.source=1.4
|
||||
|
||||
maven.junit.fork = true
|
||||
|
||||
# use Sun coding standards
|
||||
|
||||
checkstyle.lcurly.type = eol
|
||||
checkstyle.lcurly.method = eol
|
||||
checkstyle.lcurly.other = eol
|
||||
checkstyle.header.ignore.line = 1,2,3,4,5,6
|
||||
checkstyle.const.pattern = ^[a-z][a-zA-Z0-9]*$
|
||||
|
||||
# disable these non-critical errors to highlight
|
||||
# more important ones line missing javadoc
|
||||
|
||||
checkstyle.maxlinelen = 132
|
||||
checkstyle.ignore.whitespace = true
|
||||
#maven.checkstyle.ignore.public.in.interface = true
|
||||
checkstyle.paren.pad = ignore
|
||||
|
||||
#####################################################
|
||||
# codehaus theme
|
||||
#####################################################
|
||||
maven.xdoc.theme.url=http://codehaus.org/codehaus-style.css
|
||||
|
||||
maven.repo.central = dist.codehaus.org
|
||||
maven.repo.central.directory = /dist
|
||||
|
||||
maven.remote.group = activecluster
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project>
|
||||
<pomVersion>3</pomVersion>
|
||||
<name>ActiveCluster</name>
|
||||
<id>activecluster</id>
|
||||
<currentVersion>1.2</currentVersion>
|
||||
|
||||
<organization>
|
||||
<name>LogicBlaze, Inc.</name>
|
||||
<url>http://logicblaze.com</url>
|
||||
<logo>http://logicblaze.com/images/logo.jpg</logo>
|
||||
</organization>
|
||||
<logo></logo>
|
||||
|
||||
<inceptionYear>2004</inceptionYear>
|
||||
|
||||
<package>org.activecluster</package>
|
||||
<packageGroups>
|
||||
<packageGroup>
|
||||
<title>Core ActiveCluster API</title>
|
||||
<packages>org.activecluster</packages>
|
||||
</packageGroup>
|
||||
<packageGroup>
|
||||
<title>Group organisation protocols</title>
|
||||
<packages>org.activecluster.group</packages>
|
||||
</packageGroup>
|
||||
<packageGroup>
|
||||
<title>Election protocols</title>
|
||||
<packages>org.activecluster.election</packages>
|
||||
</packageGroup>
|
||||
<packageGroup>
|
||||
<title>ActiveMQ specific implementation classes</title>
|
||||
<packages>org.activecluster.activemq</packages>
|
||||
</packageGroup>
|
||||
<packageGroup>
|
||||
<title>Implementation classes</title>
|
||||
<packages>org.activecluster.impl:org.activecluster.election.impl</packages>
|
||||
</packageGroup>
|
||||
</packageGroups>
|
||||
|
||||
<shortDescription>ActiveCluster is a framework for building cluster-aware software</shortDescription>
|
||||
|
||||
<gumpRepositoryId>activecluster</gumpRepositoryId>
|
||||
|
||||
<description>
|
||||
ActiveCluster is a framework for building cluster-aware software
|
||||
</description>
|
||||
|
||||
<url>http://activecluster.codehaus.org/</url>
|
||||
<issueTrackingUrl>http://jira.codehaus.org/browse/ACL</issueTrackingUrl>
|
||||
|
||||
<siteAddress>beaver.codehaus.org</siteAddress>
|
||||
<siteDirectory>/home/projects/activecluster/public_html/maven</siteDirectory>
|
||||
<distributionDirectory>/home/projects/activecluster/dist</distributionDirectory>
|
||||
|
||||
<repository>
|
||||
<connection>scm:cvs:pserver:anonymous@cvs.activecluster.codehaus.org:/home/projects/activecluster/scm:activecluster</connection>
|
||||
<developerConnection>scm:cvs:ext:${maven.username}@cvs.activecluster.codehaus.org:/home/projects/activecluster/scm:activecluster</developerConnection>
|
||||
<url>http://cvs.activecluster.codehaus.org/</url>
|
||||
</repository>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>ActiveCluster Developer List</name>
|
||||
<subscribe>dev-subscribe@activecluster.codehaus.org</subscribe>
|
||||
<unsubscribe>dev-unsubscribe@activecluster.codehaus.org</unsubscribe>
|
||||
<archive>http://archive.activecluster.codehaus.org/dev/</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>ActiveCluster User List</name>
|
||||
<subscribe>user-subscribe@activecluster.codehaus.org</subscribe>
|
||||
<unsubscribe>user-unsubscribe@activecluster.codehaus.org</unsubscribe>
|
||||
<archive>http://archive.activecluster.codehaus.org/user/</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>ActiveCluster SCM List</name>
|
||||
<subscribe>scm-subscribe@activecluster.codehaus.org</subscribe>
|
||||
<unsubscribe>scm-unsubscribe@activecluster.codehaus.org</unsubscribe>
|
||||
<archive>http://archive.activecluster.codehaus.org/scm/</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
|
||||
|
||||
<versions>
|
||||
<version>
|
||||
<id>1.0</id>
|
||||
<name>1.0</name>
|
||||
<tag>ACTIVECLUSTER_1_0</tag>
|
||||
</version>
|
||||
<version>
|
||||
<id>1.2</id>
|
||||
<name>1.2</name>
|
||||
<tag>ACTIVECLUSTER_1_2</tag>
|
||||
</version>
|
||||
</versions>
|
||||
<branches></branches>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>James Strachan</name>
|
||||
<id>jstrachan</id>
|
||||
<email>jstrachan@logicblaze.com</email>
|
||||
<organization>LogicBlaze, Inc.</organization>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Hiram Chirino</name>
|
||||
<id>chirino</id>
|
||||
<email>hiram@logicblaze.com</email>
|
||||
<organization>LogicBlaze, Inc.</organization>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Rob Davies</name>
|
||||
<id>Rob</id>
|
||||
<email>rajdavies@gmail.com</email>
|
||||
<organization>RAJD Consultancy Ltd</organization>
|
||||
</developer>
|
||||
|
||||
<developer>
|
||||
<name>Jules Gosnell</name>
|
||||
<id>jules</id>
|
||||
<email>jules@coredevelopers.net</email>
|
||||
<organization>Core Developers Network</organization>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<contributors>
|
||||
</contributors>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.0.4</version>
|
||||
<url>http://jakarta.apache.org/commons/logging/</url>
|
||||
</dependency>
|
||||
|
||||
<!-- lets use freely distributable J2EE jars -->
|
||||
<dependency>
|
||||
<id>geronimo-spec+jms</id>
|
||||
<version>1.1-rc4</version>
|
||||
<properties>
|
||||
<war.bundle>true</war.bundle>
|
||||
</properties>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<id>geronimo-spec+jta</id>
|
||||
<version>1.0.1B-rc4</version>
|
||||
<properties>
|
||||
<war.bundle>true</war.bundle>
|
||||
</properties>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<id>geronimo-spec+j2ee-management</id>
|
||||
<version>1.0-rc4</version>
|
||||
<properties>
|
||||
<war.bundle>true</war.bundle>
|
||||
</properties>
|
||||
</dependency>
|
||||
|
||||
<!-- default JMS provider used for implementation -->
|
||||
<dependency>
|
||||
<groupId>activemq</groupId>
|
||||
<artifactId>activemq-core</artifactId>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>activeio</groupId>
|
||||
<artifactId>activeio</artifactId>
|
||||
<version>2.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- for unit test cases -->
|
||||
<dependency>
|
||||
<id>junit</id>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<!--concurrency -->
|
||||
<dependency>
|
||||
<id>backport-util-concurrent</id>
|
||||
<version>2.0_01_pd</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<nagEmailAddress>scm@activecluster.codehaus.org</nagEmailAddress>
|
||||
<sourceDirectory>src/java</sourceDirectory>
|
||||
<unitTestSourceDirectory>src/test</unitTestSourceDirectory>
|
||||
|
||||
<integrationUnitTestSourceDirectory/>
|
||||
<aspectSourceDirectory/>
|
||||
|
||||
<unitTest>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<includes>
|
||||
<include>**/*Test.*</include>
|
||||
</includes>
|
||||
</unitTest>
|
||||
|
||||
<resources>
|
||||
<!--
|
||||
<resource>
|
||||
<directory>src/jar</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
-->
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,234 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import javax.jms.BytesMessage;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MapMessage;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.ObjectMessage;
|
||||
import javax.jms.StreamMessage;
|
||||
import javax.jms.TextMessage;
|
||||
import org.activecluster.election.ElectionStrategy;
|
||||
|
||||
/**
|
||||
* Represents a logical connection to a cluster. From this object you can
|
||||
* obtain the destination to send messages to, view the members of the cluster,
|
||||
* watch cluster events (nodes joining, leaving, updating their state) as well
|
||||
* as viewing each members state.
|
||||
* <p/>
|
||||
* You may also update the local node's state.
|
||||
*
|
||||
* @version $Revision: 1.5 $
|
||||
*/
|
||||
public interface Cluster extends Service {
|
||||
|
||||
/**
|
||||
* Returns the destination used to send a message to all members of the cluster
|
||||
*
|
||||
* @return the destination to send messages to all members of the cluster
|
||||
*/
|
||||
public String getDestination();
|
||||
|
||||
/**
|
||||
* A snapshot of the nodes in the cluster indexed by the Destination
|
||||
* @return a Map containing all the nodes in the cluster, where key=node destination,value=node
|
||||
*/
|
||||
public Map getNodes();
|
||||
|
||||
/**
|
||||
* Adds a new listener to cluster events
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void addClusterListener(ClusterListener listener);
|
||||
|
||||
/**
|
||||
* Removes a listener to cluster events
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void removeClusterListener(ClusterListener listener);
|
||||
|
||||
/**
|
||||
* The local Node which allows you to mutate the state or subscribe to the
|
||||
* nodes temporary queue for inbound messages direct to the Node
|
||||
* @return the Node representing this peer in the cluster
|
||||
*/
|
||||
public LocalNode getLocalNode();
|
||||
|
||||
/**
|
||||
* Allows overriding of the default election strategy with a custom
|
||||
* implementation.
|
||||
* @param strategy
|
||||
*/
|
||||
public void setElectionStrategy(ElectionStrategy strategy);
|
||||
|
||||
|
||||
// Messaging helper methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sends a message to a destination, which could be to the entire group
|
||||
* or could be a single Node's destination
|
||||
*
|
||||
* @param destination is either the group topic or a node's destination
|
||||
* @param message the message to be sent
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void send(String destination, Message message) throws JMSException;
|
||||
|
||||
|
||||
/**
|
||||
* Utility method for sending back replies in message exchanges
|
||||
*
|
||||
* @param replyTo the replyTo JMS Destination on a Message
|
||||
* @param message the message to be sent
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void send(Destination replyTo, Message message) throws JMSException;
|
||||
/**
|
||||
* Creates a consumer of all the messags sent to the given destination,
|
||||
* including messages sent via the send() messages
|
||||
*
|
||||
* @param destination
|
||||
* @return a newly created message consumer
|
||||
* @throws JMSException
|
||||
*/
|
||||
public MessageConsumer createConsumer(String destination) throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a consumer of all message sent to the given destination,
|
||||
* including messages sent via the send() message with an optional SQL 92 based selector to filter
|
||||
* messages
|
||||
*
|
||||
* @param destination
|
||||
* @param selector
|
||||
* @return a newly created message consumer
|
||||
* @throws JMSException
|
||||
*/
|
||||
public MessageConsumer createConsumer(String destination, String selector) throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a consumer of all message sent to the given destination,
|
||||
* including messages sent via the send() message with an optional SQL 92 based selector to filter
|
||||
* messages along with optionally ignoring local traffic - messages sent via the send()
|
||||
* method on this object.
|
||||
*
|
||||
* @param destination the destination to consume from
|
||||
* @param selector an optional SQL 92 filter of messages which could be null
|
||||
* @param noLocal which if true messages sent via send() on this object will not be delivered to the consumer
|
||||
* @return a newly created message consumer
|
||||
* @throws JMSException
|
||||
*/
|
||||
public MessageConsumer createConsumer(String destination, String selector, boolean noLocal) throws JMSException;
|
||||
|
||||
|
||||
// Message factory methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a new message without a body
|
||||
* @return the create Message
|
||||
*
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Message createMessage() throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new bytes message
|
||||
* @return the create BytesMessage
|
||||
*
|
||||
* @throws JMSException
|
||||
*/
|
||||
public BytesMessage createBytesMessage() throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MapMessage}
|
||||
* @return the created MapMessage
|
||||
*
|
||||
* @throws JMSException
|
||||
*/
|
||||
public MapMessage createMapMessage() throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ObjectMessage}
|
||||
* @return the created ObjectMessage
|
||||
*
|
||||
* @throws JMSException
|
||||
*/
|
||||
public ObjectMessage createObjectMessage() throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ObjectMessage}
|
||||
*
|
||||
* @param object
|
||||
* @return the createdObjectMessage
|
||||
* @throws JMSException
|
||||
*/
|
||||
public ObjectMessage createObjectMessage(Serializable object) throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new {@link StreamMessage}
|
||||
* @return the create StreamMessage
|
||||
*
|
||||
* @throws JMSException
|
||||
*/
|
||||
public StreamMessage createStreamMessage() throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TextMessage}
|
||||
* @return the create TextMessage
|
||||
*
|
||||
* @throws JMSException
|
||||
*/
|
||||
public TextMessage createTextMessage() throws JMSException;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TextMessage}
|
||||
*
|
||||
* @param text
|
||||
* @return the create TextMessage
|
||||
* @throws JMSException
|
||||
*/
|
||||
public TextMessage createTextMessage(String text) throws JMSException;
|
||||
|
||||
/**
|
||||
* Create a named Destination
|
||||
* @param name
|
||||
* @return the Destinatiion
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Destination createDestination(String name) throws JMSException;
|
||||
|
||||
/**
|
||||
* wait until a the cardimality of the cluster is reaches the expected count. This method will return false if the
|
||||
* cluster isn't started or stopped while waiting
|
||||
*
|
||||
* @param expectedCount the number of expected members of a cluster
|
||||
* @param timeout timeout in milliseconds
|
||||
* @return true if the cluster is fully connected
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
boolean waitForClusterToComplete(int expectedCount, long timeout) throws InterruptedException;
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
/**
|
||||
* A cluster event
|
||||
*
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public class ClusterEvent implements Externalizable {
|
||||
|
||||
private static final long serialVersionUID=-4103732679231950873L;
|
||||
/**
|
||||
* A node has joined the cluster
|
||||
*/
|
||||
public static final int ADD_NODE = 1;
|
||||
/**
|
||||
* existing node has updated it's state
|
||||
*/
|
||||
public static final int UPDATE_NODE = 2;
|
||||
/**
|
||||
* A node has left the Cluster
|
||||
*/
|
||||
public static final int REMOVE_NODE = 3;
|
||||
/**
|
||||
* A node has failed due to a system/network error
|
||||
*/
|
||||
public static final int FAILED_NODE = 4;
|
||||
|
||||
/**
|
||||
* this node has been elected Coordinator
|
||||
*/
|
||||
public static final int ELECTED_COORDINATOR = 5;
|
||||
|
||||
private transient Cluster cluster;
|
||||
private Node node;
|
||||
private int type;
|
||||
|
||||
/**
|
||||
* empty constructor
|
||||
*/
|
||||
public ClusterEvent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source
|
||||
* @param node
|
||||
* @param type
|
||||
*/
|
||||
public ClusterEvent(Cluster source, Node node, int type) {
|
||||
this.cluster = source;
|
||||
this.node = node;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Cluster
|
||||
*/
|
||||
public Cluster getCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the cluster
|
||||
* @param source
|
||||
*/
|
||||
public void setCluster(Cluster source){
|
||||
this.cluster = source;
|
||||
}
|
||||
/**
|
||||
* @return the node
|
||||
*/
|
||||
public Node getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type of event
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return pretty type
|
||||
*/
|
||||
public String toString() {
|
||||
return "ClusterEvent[" + getTypeAsString() + " : " + node + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* dump on to a stream
|
||||
*
|
||||
* @param out
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeByte(type);
|
||||
out.writeObject(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* read from stream
|
||||
*
|
||||
* @param in
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
type = in.readByte();
|
||||
node = (Node) in.readObject();
|
||||
}
|
||||
|
||||
private String getTypeAsString() {
|
||||
String result = "unknown type";
|
||||
if (type == ADD_NODE) {
|
||||
result = "ADD_NODE";
|
||||
}
|
||||
else if (type == REMOVE_NODE) {
|
||||
result = "REMOVE_NODE";
|
||||
}
|
||||
else if (type == UPDATE_NODE) {
|
||||
result = "UPDATE_NODE";
|
||||
}
|
||||
else if (type == FAILED_NODE) {
|
||||
result = "FAILED_NODE";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a Cluster related exception
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class ClusterException extends Exception {
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
|
||||
|
||||
/**
|
||||
* A Factory of Cluster instances
|
||||
*
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public interface ClusterFactory {
|
||||
|
||||
/**
|
||||
* Creates a new cluster connection using the given local name and destination name
|
||||
* @param localName
|
||||
* @param destination
|
||||
*
|
||||
* @return Cluster
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Cluster createCluster(String localName,String destination) throws JMSException;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new cluster connection - generating the localName automatically
|
||||
* @param destination
|
||||
* @return
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Cluster createCluster(String destination) throws JMSException;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
|
||||
/**
|
||||
* Listener to events occuring on the cluster
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public interface ClusterListener extends EventListener {
|
||||
|
||||
/**
|
||||
* A new node has been added
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void onNodeAdd(ClusterEvent event);
|
||||
|
||||
/**
|
||||
* A node has updated its state
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void onNodeUpdate(ClusterEvent event);
|
||||
|
||||
/**
|
||||
* A node has been removed (a clean shutdown)
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void onNodeRemoved(ClusterEvent event);
|
||||
|
||||
/**
|
||||
* A node has failed due to process or network failure
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void onNodeFailed(ClusterEvent event);
|
||||
|
||||
/**
|
||||
* An election has occurred and a new coordinator has been selected
|
||||
* @param event
|
||||
*/
|
||||
public void onCoordinatorChanged(ClusterEvent event);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents the local (in process) node
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public interface LocalNode extends Node {
|
||||
|
||||
/**
|
||||
* Allows the local state to be modified, which will
|
||||
* be replicated asynchronously around the cluster
|
||||
* @param state
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void setState(Map state) throws JMSException;
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a node member in a cluster
|
||||
*
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public interface Node extends Serializable {
|
||||
|
||||
/**
|
||||
* Access to the queue to send messages direct to this node.
|
||||
*
|
||||
* @return the destination to send messages to this node while its available
|
||||
*/
|
||||
public String getDestination();
|
||||
|
||||
/**
|
||||
* @return an immutable map of the nodes state
|
||||
*/
|
||||
public Map getState();
|
||||
|
||||
/**
|
||||
* @return the name of the node
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* @return true if this node has been elected as coordinator
|
||||
*/
|
||||
public boolean isCoordinator();
|
||||
|
||||
/**
|
||||
* Returns the Zone of this node - typically the DMZ zone or the subnet on which the
|
||||
* node is on
|
||||
*/
|
||||
public Object getZone();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
|
||||
/**
|
||||
* <p><code>Service</code> represents some service of some kind with a simple start/stop lifecycle.</p>
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public interface Service {
|
||||
|
||||
/**
|
||||
* Called to start the service
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void start() throws JMSException;
|
||||
|
||||
/**
|
||||
* Called to shutdown the service
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void stop() throws JMSException;
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.election;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.Node;
|
||||
|
||||
/**
|
||||
* <p><code>Service</code> Used by the Cluster to elect a coordinator.</p>
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public interface ElectionStrategy {
|
||||
|
||||
/**
|
||||
* Elect a coordinator.
|
||||
* @param cluster
|
||||
* @return the elected Node
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Node doElection(Cluster cluster) throws JMSException;
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.election.impl;
|
||||
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.Node;
|
||||
import org.activecluster.election.ElectionStrategy;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p><code>BullyElectionStrategy</code> Use a simple bully algorithm to elect a coordinator.
|
||||
* the member with the lowest lexicographical name is choosen</p>
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class BullyElectionStrategy implements ElectionStrategy {
|
||||
|
||||
/**
|
||||
* Elect a coordinator.
|
||||
*
|
||||
* @param cluster
|
||||
* @return the elected Node
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Node doElection(Cluster cluster) throws JMSException {
|
||||
Node elect = cluster.getLocalNode();
|
||||
|
||||
Map nodes = cluster.getNodes();
|
||||
for (Iterator i = nodes.values().iterator(); i.hasNext();) {
|
||||
Node node = (Node) i.next();
|
||||
if (elect.getName().compareTo(node.getName()) < 0) {
|
||||
elect = node;
|
||||
}
|
||||
}
|
||||
|
||||
return elect;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
/**
|
||||
* A kind of {@link GroupModel} in which every {@link Node} has its
|
||||
* own {@link Group} and other nodes in the cluster act as buddies (slaves)
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class BuddyGroupModel extends GroupModel {
|
||||
|
||||
public synchronized void addNode(Node node) {
|
||||
Group group = makeNewGroup(node);
|
||||
if (group == null) {
|
||||
if (!addToExistingGroup(node)) {
|
||||
addToUnusedNodes(node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// now lets try choose some existing nodes to add as buddy's
|
||||
tryToFillGroupWithBuddies(group);
|
||||
|
||||
// now that the group may well be filled, add it to the collections
|
||||
addGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a logical group of nodes in a cluster,
|
||||
* such as a Master and a number of Slaves which operate as a
|
||||
* logical unit.
|
||||
* <p/>
|
||||
* A cluster can be divided into a single group, or many groups
|
||||
* depending on the policy required.
|
||||
* <p/>
|
||||
* The number of groups could be application defined; created on demand
|
||||
* or there could even be one group for each node, with other nodes acting
|
||||
* as buddy nodes in each nodes' group (i.e. each node is a master with N
|
||||
* buddies/slaves)
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class Group {
|
||||
private int minimumMemberCount;
|
||||
private int maximumMemberCount;
|
||||
private List members = new ArrayList();
|
||||
private int memberCount;
|
||||
|
||||
public Group() {
|
||||
}
|
||||
|
||||
public Group(int minimumMemberCount, int maximumMemberCount) {
|
||||
this.minimumMemberCount = minimumMemberCount;
|
||||
this.maximumMemberCount = maximumMemberCount;
|
||||
}
|
||||
|
||||
public synchronized List getMembers() {
|
||||
return new ArrayList(members);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node to the given group
|
||||
*
|
||||
* @return the index of the node in the group (0 = master, 1..N = slave)
|
||||
*/
|
||||
public synchronized int addMember(Node node) {
|
||||
int index = members.indexOf(node);
|
||||
if (index >= 0) {
|
||||
return index;
|
||||
}
|
||||
members.add(node);
|
||||
return memberCount++;
|
||||
}
|
||||
|
||||
public synchronized boolean removeMember(Node node) {
|
||||
boolean answer = members.remove(node);
|
||||
if (answer) {
|
||||
memberCount--;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the group is usable, that it has enough members to be used.
|
||||
*/
|
||||
public boolean isUsable() {
|
||||
return memberCount >= minimumMemberCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the group cannot accept any more new members
|
||||
*/
|
||||
public boolean isFull() {
|
||||
return memberCount >= maximumMemberCount;
|
||||
}
|
||||
|
||||
public int getMemberCount() {
|
||||
return memberCount;
|
||||
}
|
||||
|
||||
public int getMaximumMemberCount() {
|
||||
return maximumMemberCount;
|
||||
}
|
||||
|
||||
public void setMaximumMemberCount(int maximumMemberCount) {
|
||||
this.maximumMemberCount = maximumMemberCount;
|
||||
}
|
||||
|
||||
public int getMinimumMemberCount() {
|
||||
return minimumMemberCount;
|
||||
}
|
||||
|
||||
public void setMinimumMemberCount(int minimumMemberCount) {
|
||||
this.minimumMemberCount = minimumMemberCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.ClusterEvent;
|
||||
import org.activecluster.ClusterListener;
|
||||
|
||||
/**
|
||||
* A {@link ClusterListener} which maintains a {@link GroupModel} implementation
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class GroupClusterListener implements ClusterListener {
|
||||
private GroupModel model;
|
||||
|
||||
public GroupClusterListener(GroupModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
public GroupModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
// ClusterListener interface
|
||||
//-------------------------------------------------------------------------
|
||||
public void onNodeAdd(ClusterEvent event) {
|
||||
model.addNode(event.getNode());
|
||||
}
|
||||
|
||||
public void onNodeUpdate(ClusterEvent event) {
|
||||
}
|
||||
|
||||
public void onNodeRemoved(ClusterEvent event) {
|
||||
model.removeNode(event.getNode());
|
||||
}
|
||||
|
||||
public void onNodeFailed(ClusterEvent event) {
|
||||
model.removeNode(event.getNode());
|
||||
}
|
||||
|
||||
public void onCoordinatorChanged(ClusterEvent event) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a collection of zero or more groups in a cluster.
|
||||
* The default implementation will create groups as nodes are added to the cluster; filling
|
||||
* the groups with its required number of buddies / slaves until a new group can be created.
|
||||
* <p/>
|
||||
* Nodes which are not allowed to be master nodes will be kept around in a pool ready to be added
|
||||
* as slaves when a new master arrives and forces the creation of a group.
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
* @see Group
|
||||
*/
|
||||
public class GroupModel {
|
||||
private int maximumGroups = -1;
|
||||
private int minimumMemberCount = 2;
|
||||
private int maximumMemberCount = 3;
|
||||
private List groups = new ArrayList();
|
||||
private LinkedList incompleteGroups = new LinkedList();
|
||||
private LinkedList completeGroups = new LinkedList();
|
||||
private LinkedList fullGroups = new LinkedList();
|
||||
private LinkedList unusedNodes = new LinkedList();
|
||||
private NodeFilter masterFilter;
|
||||
private Map nodeMemberships = new HashMap();
|
||||
|
||||
// allow a node to be a master and 2 buddies
|
||||
private int maximumWeighting = 10;
|
||||
|
||||
/**
|
||||
* Adds the new node to this group model; we assume the node has not been added before.
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
public synchronized void addNode(Node node) {
|
||||
if (!addToExistingGroup(node)) {
|
||||
Group group = makeNewGroup(node);
|
||||
if (group == null) {
|
||||
addToUnusedNodes(node);
|
||||
}
|
||||
else {
|
||||
addGroup(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the node from the group model
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
public synchronized void removeNode(Node node) {
|
||||
unusedNodes.remove(node);
|
||||
|
||||
// lets remove the node from each group
|
||||
for (Iterator iter = groups.iterator(); iter.hasNext();) {
|
||||
Group group = (Group) iter.next();
|
||||
boolean wasFull = group.isFull();
|
||||
boolean wasUsable = group.isUsable();
|
||||
|
||||
if (removeNodeFromGroup(group, node)) {
|
||||
updateGroupCollections(group, wasFull, wasUsable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the groups currently available
|
||||
*/
|
||||
public synchronized List getGroups() {
|
||||
return new ArrayList(groups);
|
||||
}
|
||||
|
||||
public NodeFilter getMasterFilter() {
|
||||
return masterFilter;
|
||||
}
|
||||
|
||||
public void setMasterFilter(NodeFilter masterFilter) {
|
||||
this.masterFilter = masterFilter;
|
||||
}
|
||||
|
||||
public int getMaximumGroups() {
|
||||
return maximumGroups;
|
||||
}
|
||||
|
||||
public void setMaximumGroups(int maximumGroups) {
|
||||
this.maximumGroups = maximumGroups;
|
||||
}
|
||||
|
||||
public int getMaximumMemberCount() {
|
||||
return maximumMemberCount;
|
||||
}
|
||||
|
||||
public void setMaximumMemberCount(int maximumMemberCount) {
|
||||
this.maximumMemberCount = maximumMemberCount;
|
||||
}
|
||||
|
||||
public int getMinimumMemberCount() {
|
||||
return minimumMemberCount;
|
||||
}
|
||||
|
||||
public void setMinimumMemberCount(int minimumMemberCount) {
|
||||
this.minimumMemberCount = minimumMemberCount;
|
||||
}
|
||||
|
||||
public int getMaximumWeighting() {
|
||||
return maximumWeighting;
|
||||
}
|
||||
|
||||
public void setMaximumWeighting(int maximumWeighting) {
|
||||
this.maximumWeighting = maximumWeighting;
|
||||
}
|
||||
|
||||
|
||||
// Implementation methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to make a new group with the current node as the master
|
||||
* or if the node cannot be a master node
|
||||
*
|
||||
* @return the newly created group or false if none was created.
|
||||
*/
|
||||
protected Group makeNewGroup(Node node) {
|
||||
// no pending groups available so lets try and create a new group
|
||||
if (canCreateGroup(node)) {
|
||||
Group group = createGroup(node);
|
||||
addNodeToGroup(group, node);
|
||||
return group;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void tryToFillGroupWithBuddies(Group group) {
|
||||
boolean continueFillingGroups = true;
|
||||
while (!group.isUsable() && continueFillingGroups) {
|
||||
continueFillingGroups = tryToAddBuddy(group);
|
||||
}
|
||||
|
||||
if (continueFillingGroups) {
|
||||
// lets try fill more unfilled nodes
|
||||
for (Iterator iter = new ArrayList(incompleteGroups).iterator(); iter.hasNext() && continueFillingGroups;) {
|
||||
group = (Group) iter.next();
|
||||
|
||||
boolean wasFull = group.isFull();
|
||||
boolean wasUsable = group.isUsable();
|
||||
|
||||
while (!group.isUsable() && continueFillingGroups) {
|
||||
continueFillingGroups = tryToAddBuddy(group);
|
||||
}
|
||||
|
||||
if (group.isUsable()) {
|
||||
updateGroupCollections(group, wasFull, wasUsable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean tryToAddBuddy(Group group) {
|
||||
boolean continueFillingGroups = true;
|
||||
// TODO we could make this much faster using a weighting-sorted collection
|
||||
NodeMemberships lowest = null;
|
||||
int lowestWeight = 0;
|
||||
for (Iterator iter = nodeMemberships.values().iterator(); iter.hasNext();) {
|
||||
NodeMemberships memberships = (NodeMemberships) iter.next();
|
||||
if (!memberships.isMember(group)) {
|
||||
int weighting = memberships.getWeighting();
|
||||
if ((lowest == null || weighting < lowestWeight) && weighting < maximumWeighting) {
|
||||
lowest = memberships;
|
||||
lowestWeight = weighting;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lowest == null) {
|
||||
continueFillingGroups = false;
|
||||
}
|
||||
else {
|
||||
addNodeToGroup(group, lowest.getNode());
|
||||
}
|
||||
return continueFillingGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets move the group from its current state collection to the new collection if its
|
||||
* state has changed
|
||||
*/
|
||||
protected void updateGroupCollections(Group group, boolean wasFull, boolean wasUsable) {
|
||||
boolean full = group.isFull();
|
||||
if (wasFull && !full) {
|
||||
fullGroups.remove(group);
|
||||
}
|
||||
boolean usable = group.isUsable();
|
||||
if (wasUsable && !usable) {
|
||||
completeGroups.remove(group);
|
||||
}
|
||||
if ((!usable || !full) && (wasFull || wasUsable)) {
|
||||
incompleteGroups.add(group);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addToUnusedNodes(Node node) {
|
||||
// lets add the node to the pool ready to be used if a node fails
|
||||
unusedNodes.add(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to add the node to an incomplete group, or
|
||||
* a not-full group and returns true if its possible - else returns false
|
||||
*
|
||||
* @return true if the node has been added to a groupu
|
||||
*/
|
||||
protected boolean addToExistingGroup(Node node) {
|
||||
if (!addToIncompleteGroup(node)) {
|
||||
if (!addToNotFullGroup(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean addToNotFullGroup(Node node) {
|
||||
return addToPendingGroup(completeGroups, node);
|
||||
}
|
||||
|
||||
protected boolean addToIncompleteGroup(Node node) {
|
||||
return addToPendingGroup(incompleteGroups, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given node to the first pending group if possible
|
||||
*
|
||||
* @return true if the node was added to the first available group
|
||||
*/
|
||||
protected boolean addToPendingGroup(LinkedList list, Node node) {
|
||||
if (!list.isEmpty()) {
|
||||
Group group = (Group) list.getFirst();
|
||||
addNodeToGroup(group, node);
|
||||
if (group.isFull()) {
|
||||
list.removeFirst();
|
||||
fullGroups.add(group);
|
||||
}
|
||||
else if (group.isUsable()) {
|
||||
list.removeFirst();
|
||||
completeGroups.add(group);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void addNodeToGroup(Group group, Node node) {
|
||||
NodeMemberships memberships = (NodeMemberships) nodeMemberships.get(node);
|
||||
if (memberships == null) {
|
||||
memberships = new NodeMemberships(node);
|
||||
nodeMemberships.put(node, memberships);
|
||||
}
|
||||
memberships.addToGroup(group);
|
||||
}
|
||||
|
||||
protected boolean removeNodeFromGroup(Group group, Node node) {
|
||||
NodeMemberships memberships = (NodeMemberships) nodeMemberships.get(node);
|
||||
if (memberships != null) {
|
||||
return memberships.removeFromGroup(group);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected void addGroup(Group group) {
|
||||
groups.add(group);
|
||||
if (group.isFull()) {
|
||||
fullGroups.add(group);
|
||||
}
|
||||
else if (group.isUsable()) {
|
||||
completeGroups.add(group);
|
||||
}
|
||||
else {
|
||||
incompleteGroups.add(group);
|
||||
}
|
||||
}
|
||||
|
||||
protected Group createGroup(Node node) {
|
||||
return new Group(minimumMemberCount, maximumMemberCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we can add a new group to the cluster
|
||||
*/
|
||||
protected boolean canCreateGroup(Node node) {
|
||||
return (maximumGroups < 0 || groups.size() < maximumGroups) && canBeMaster(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given node can be a master
|
||||
*/
|
||||
protected boolean canBeMaster(Node node) {
|
||||
return masterFilter == null || masterFilter.evaluate(node);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A filter configured with a list of DMZ zones on which to restrict which nodes
|
||||
* are allowed to be master nodes.
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class MasterZoneFilter implements NodeFilter {
|
||||
private List zones;
|
||||
|
||||
public MasterZoneFilter(List zones) {
|
||||
this.zones = zones;
|
||||
}
|
||||
|
||||
public boolean evaluate(Node node) {
|
||||
Object zone = node.getZone();
|
||||
return zones.contains(zone);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
/**
|
||||
* Represents the membership of a Group for a Node
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class Membership {
|
||||
public static final int STATUS_REQUESTED = 1;
|
||||
public static final int STATUS_SYNCHONIZING = 2;
|
||||
public static final int STATUS_FAILED = 3;
|
||||
public static final int STATUS_OK = 4;
|
||||
|
||||
private Group group;
|
||||
private int index;
|
||||
private int status = STATUS_REQUESTED;
|
||||
|
||||
public Membership(Group group, int index) {
|
||||
this.group = group;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the weighting of this membership
|
||||
*/
|
||||
public int getWeighting() {
|
||||
// lets make master heavy and the further from the end of the
|
||||
// list of slaves, the lighter we become
|
||||
return group.getMaximumMemberCount() - getIndex();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
/**
|
||||
* Represents a filter on a Node to allow a pluggable
|
||||
* Strategy Pattern to decide which nodes can be master nodes etc.
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public interface NodeFilter {
|
||||
|
||||
/**
|
||||
* Returns true if the given node matches the filter
|
||||
*/
|
||||
public boolean evaluate(Node node);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents all of the memberhips of a node and can be used to act
|
||||
* as a weighting to decide which is the least heavily loaded Node
|
||||
* to be assigned to a buddy group.
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class NodeMemberships {
|
||||
private Node node;
|
||||
private Map memberships = new HashMap();
|
||||
private int weighting;
|
||||
|
||||
public NodeMemberships(Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public void addToGroup(Group group) {
|
||||
if (!isMember(group)) {
|
||||
int index = group.addMember(node);
|
||||
Membership membership = new Membership(group, index);
|
||||
memberships.put(group, membership);
|
||||
weighting += membership.getWeighting();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeFromGroup(Group group) {
|
||||
// TODO when we remove a node from a group, we need to reweight the
|
||||
// other nodes in the group
|
||||
|
||||
memberships.remove(group);
|
||||
return group.removeMember(node);
|
||||
}
|
||||
|
||||
public Node getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the weighting of how heavily loaded the node is
|
||||
* so that a decision can be made on which node to buddy group
|
||||
* with
|
||||
*/
|
||||
public int getWeighting() {
|
||||
return weighting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this node is a member of the given group
|
||||
*/
|
||||
public boolean isMember(Group group) {
|
||||
return memberships.containsKey(group);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Contains Group Organsisation models and policies for arranging {@link org.activecluster.Node} instances into
|
||||
groups, such as buddy-groups (failover nodes) or master/slave groups for High Availability (HA) protocols.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import org.activecluster.impl.DefaultClusterFactory;
|
||||
import org.activemq.ActiveMQConnectionFactory;
|
||||
|
||||
/**
|
||||
* An implementation of {@link org.activecluster.ClusterFactory} using
|
||||
* <a href="http://activemq.codehaus.org/">ActiveMQ</a>
|
||||
*
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class ActiveMQClusterFactory extends DefaultClusterFactory {
|
||||
|
||||
public static String DEFAULT_CLUSTER_URL = "peer://org.activecluster?persistent=false";
|
||||
|
||||
public ActiveMQClusterFactory() {
|
||||
super(new ActiveMQConnectionFactory(DEFAULT_CLUSTER_URL));
|
||||
}
|
||||
|
||||
public ActiveMQClusterFactory(String brokerURL) {
|
||||
super(new ActiveMQConnectionFactory(brokerURL));
|
||||
}
|
||||
|
||||
public ActiveMQClusterFactory(ActiveMQConnectionFactory connectionFactory) {
|
||||
super(connectionFactory);
|
||||
}
|
||||
|
||||
public ActiveMQClusterFactory(boolean transacted, int acknowledgeMode, String dataTopicPrefix, long inactiveTime) {
|
||||
super(new ActiveMQConnectionFactory(DEFAULT_CLUSTER_URL), transacted, acknowledgeMode, dataTopicPrefix, inactiveTime);
|
||||
}
|
||||
|
||||
public ActiveMQClusterFactory(ActiveMQConnectionFactory connectionFactory, boolean transacted, int acknowledgeMode, String dataTopicPrefix, long inactiveTime) {
|
||||
super(connectionFactory, transacted, acknowledgeMode, dataTopicPrefix, inactiveTime);
|
||||
}
|
||||
|
||||
public ActiveMQConnectionFactory getActiveMQConnectionFactory() {
|
||||
return (ActiveMQConnectionFactory) getConnectionFactory();
|
||||
}
|
||||
|
||||
public void setActiveMQConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
|
||||
setConnectionFactory(connectionFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import javax.jms.BytesMessage;
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MapMessage;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.ObjectMessage;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.StreamMessage;
|
||||
import javax.jms.TextMessage;
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.ClusterListener;
|
||||
import org.activecluster.LocalNode;
|
||||
import org.activecluster.Service;
|
||||
import org.activecluster.election.ElectionStrategy;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.atomic.*;
|
||||
/**
|
||||
* A default implementation of ActiveCluster which uses standard JMS operations
|
||||
*
|
||||
* @version $Revision: 1.6 $
|
||||
*/
|
||||
public class DefaultCluster implements Cluster {
|
||||
|
||||
private final static Log log = LogFactory.getLog(DefaultCluster.class);
|
||||
|
||||
private StateServiceImpl stateService;
|
||||
private LocalNode localNode;
|
||||
private String destination;
|
||||
private Connection connection;
|
||||
private Session session;
|
||||
private MessageProducer producer;
|
||||
private MessageConsumer consumer;
|
||||
private Timer timer;
|
||||
private AtomicBoolean started = new AtomicBoolean(false);
|
||||
private Object clusterLock = new Object();
|
||||
|
||||
public DefaultCluster(final LocalNode localNode,String dataDestination, String destination, Connection connection, Session session,
|
||||
MessageProducer producer, Timer timer, long inactiveTime) throws JMSException {
|
||||
this.localNode = localNode;
|
||||
this.destination = destination;
|
||||
this.connection = connection;
|
||||
this.session = session;
|
||||
this.producer = producer;
|
||||
this.timer = timer;
|
||||
|
||||
if (producer == null) {
|
||||
throw new IllegalArgumentException("No producer specified!");
|
||||
}
|
||||
|
||||
// now lets subscribe the service to the updates from the data topic
|
||||
consumer = session.createConsumer(createDestination(dataDestination), null, true);
|
||||
|
||||
log.info("Creating data consumer on topic: " + dataDestination);
|
||||
|
||||
this.stateService = new StateServiceImpl(this, clusterLock, new Runnable() {
|
||||
public void run() {
|
||||
if (localNode instanceof ReplicatedLocalNode) {
|
||||
((ReplicatedLocalNode) localNode).pingRemoteNodes();
|
||||
}
|
||||
}
|
||||
}, timer, inactiveTime);
|
||||
consumer.setMessageListener(new StateConsumer(stateService));
|
||||
}
|
||||
|
||||
public void addClusterListener(ClusterListener listener) {
|
||||
stateService.addClusterListener(listener);
|
||||
}
|
||||
|
||||
public void removeClusterListener(ClusterListener listener) {
|
||||
stateService.removeClusterListener(listener);
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public LocalNode getLocalNode() {
|
||||
return localNode;
|
||||
}
|
||||
|
||||
public Map getNodes() {
|
||||
return stateService.getNodes();
|
||||
}
|
||||
|
||||
public void setElectionStrategy(ElectionStrategy strategy) {
|
||||
stateService.setElectionStrategy(strategy);
|
||||
}
|
||||
|
||||
public void send(String destination,Message message) throws JMSException {
|
||||
producer.send(createDestination(destination), message);
|
||||
}
|
||||
|
||||
public void send(Destination replyTo, Message message) throws JMSException{
|
||||
producer.send(replyTo,message);
|
||||
}
|
||||
|
||||
public MessageConsumer createConsumer(String destination) throws JMSException {
|
||||
return getSession().createConsumer(createDestination(destination));
|
||||
}
|
||||
|
||||
public MessageConsumer createConsumer(String destination, String selector) throws JMSException {
|
||||
return getSession().createConsumer(createDestination(destination), selector);
|
||||
}
|
||||
|
||||
public MessageConsumer createConsumer(String destination, String selector, boolean noLocal) throws JMSException {
|
||||
return getSession().createConsumer(createDestination(destination), selector, noLocal);
|
||||
}
|
||||
|
||||
public Message createMessage() throws JMSException {
|
||||
return getSession().createMessage();
|
||||
}
|
||||
|
||||
public BytesMessage createBytesMessage() throws JMSException {
|
||||
return getSession().createBytesMessage();
|
||||
}
|
||||
|
||||
public MapMessage createMapMessage() throws JMSException {
|
||||
return getSession().createMapMessage();
|
||||
}
|
||||
|
||||
public ObjectMessage createObjectMessage() throws JMSException {
|
||||
return getSession().createObjectMessage();
|
||||
}
|
||||
|
||||
public ObjectMessage createObjectMessage(Serializable object) throws JMSException {
|
||||
return getSession().createObjectMessage(object);
|
||||
}
|
||||
|
||||
public StreamMessage createStreamMessage() throws JMSException {
|
||||
return getSession().createStreamMessage();
|
||||
}
|
||||
|
||||
public TextMessage createTextMessage() throws JMSException {
|
||||
return getSession().createTextMessage();
|
||||
}
|
||||
|
||||
public TextMessage createTextMessage(String text) throws JMSException {
|
||||
return getSession().createTextMessage(text);
|
||||
}
|
||||
|
||||
public void start() throws JMSException {
|
||||
if (started.compareAndSet(false, true)) {
|
||||
connection.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() throws JMSException {
|
||||
try {
|
||||
if (localNode instanceof Service) {
|
||||
((Service) localNode).stop();
|
||||
}
|
||||
timer.cancel();
|
||||
session.close();
|
||||
connection.stop();
|
||||
connection.close();
|
||||
}
|
||||
finally {
|
||||
connection = null;
|
||||
session = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean waitForClusterToComplete(int expectedCount, long timeout) throws InterruptedException {
|
||||
timeout = timeout > 0 ? timeout : Long.MAX_VALUE;
|
||||
long increment = 500;
|
||||
increment = increment < timeout ? increment : timeout;
|
||||
long waitTime = timeout;
|
||||
long start = System.currentTimeMillis();
|
||||
synchronized (clusterLock) {
|
||||
while (stateService.getNodes().size() < expectedCount && started.get() && waitTime > 0) {
|
||||
clusterLock.wait(increment);
|
||||
waitTime = timeout - (System.currentTimeMillis() - start);
|
||||
}
|
||||
}
|
||||
return stateService.getNodes().size() >= expectedCount;
|
||||
}
|
||||
|
||||
protected Session getSession() throws JMSException {
|
||||
if (session == null) {
|
||||
throw new JMSException("Cannot perform operation, this cluster connection is now closed");
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named Destination
|
||||
* @param name
|
||||
* @return the Destinatiion
|
||||
* @throws JMSException
|
||||
*/
|
||||
public Destination createDestination(String name) throws JMSException{
|
||||
Destination result = getSession().createTopic(name);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import java.util.Timer;
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.DeliveryMode;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.Topic;
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.ClusterException;
|
||||
import org.activecluster.ClusterFactory;
|
||||
import org.activemq.util.IdGenerator;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A Factory of DefaultCluster instances
|
||||
*
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class DefaultClusterFactory implements ClusterFactory {
|
||||
|
||||
private final static Log log = LogFactory.getLog(DefaultClusterFactory.class);
|
||||
|
||||
private ConnectionFactory connectionFactory;
|
||||
private boolean transacted;
|
||||
private int acknowledgeMode;
|
||||
private String dataTopicPrefix;
|
||||
private long inactiveTime;
|
||||
private boolean useQueueForInbox = false;
|
||||
private int deliveryMode = DeliveryMode.NON_PERSISTENT;
|
||||
private IdGenerator idGenerator = new IdGenerator();
|
||||
|
||||
public DefaultClusterFactory(ConnectionFactory connectionFactory, boolean transacted, int acknowledgeMode, String dataTopicPrefix, long inactiveTime) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.transacted = transacted;
|
||||
this.acknowledgeMode = acknowledgeMode;
|
||||
this.dataTopicPrefix = dataTopicPrefix;
|
||||
this.inactiveTime = inactiveTime;
|
||||
}
|
||||
|
||||
public DefaultClusterFactory(ConnectionFactory connectionFactory) {
|
||||
this(connectionFactory, false, Session.AUTO_ACKNOWLEDGE, "ACTIVECLUSTER.DATA.", 6000L);
|
||||
}
|
||||
|
||||
public Cluster createCluster(String groupDestination) throws JMSException {
|
||||
return createCluster(idGenerator.generateId(), groupDestination);
|
||||
}
|
||||
|
||||
public Cluster createCluster(String name,String groupDestination) throws JMSException {
|
||||
Connection connection = getConnectionFactory().createConnection();
|
||||
Session session = createSession(connection);
|
||||
return createCluster(connection, session, name,groupDestination);
|
||||
}
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
public String getDataTopicPrefix() {
|
||||
return dataTopicPrefix;
|
||||
}
|
||||
|
||||
public void setDataTopicPrefix(String dataTopicPrefix) {
|
||||
this.dataTopicPrefix = dataTopicPrefix;
|
||||
}
|
||||
|
||||
public int getAcknowledgeMode() {
|
||||
return acknowledgeMode;
|
||||
}
|
||||
|
||||
public void setAcknowledgeMode(int acknowledgeMode) {
|
||||
this.acknowledgeMode = acknowledgeMode;
|
||||
}
|
||||
|
||||
public long getInactiveTime() {
|
||||
return inactiveTime;
|
||||
}
|
||||
|
||||
public void setInactiveTime(long inactiveTime) {
|
||||
this.inactiveTime = inactiveTime;
|
||||
}
|
||||
|
||||
public boolean isTransacted() {
|
||||
return transacted;
|
||||
}
|
||||
|
||||
public void setTransacted(boolean transacted) {
|
||||
this.transacted = transacted;
|
||||
}
|
||||
|
||||
public boolean isUseQueueForInbox() {
|
||||
return useQueueForInbox;
|
||||
}
|
||||
|
||||
public void setUseQueueForInbox(boolean useQueueForInbox) {
|
||||
this.useQueueForInbox = useQueueForInbox;
|
||||
}
|
||||
|
||||
public ConnectionFactory getConnectionFactory() {
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
public void setConnectionFactory(ConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
public int getDeliveryMode() {
|
||||
return deliveryMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delivery mode of the group based producer
|
||||
*/
|
||||
public void setDeliveryMode(int deliveryMode) {
|
||||
this.deliveryMode = deliveryMode;
|
||||
}
|
||||
|
||||
// Implementation methods
|
||||
//-------------------------------------------------------------------------
|
||||
protected Cluster createCluster(Connection connection, Session session, String name,String groupDestination) throws JMSException {
|
||||
String dataDestination = dataTopicPrefix + groupDestination;
|
||||
|
||||
log.info("Creating cluster group producer on topic: " + groupDestination);
|
||||
|
||||
MessageProducer producer = createProducer(session, null);
|
||||
producer.setDeliveryMode(deliveryMode);
|
||||
|
||||
log.info("Creating cluster data producer on data destination: " + dataDestination);
|
||||
|
||||
Topic dataTopic = session.createTopic(dataDestination);
|
||||
MessageProducer keepAliveProducer = session.createProducer(dataTopic);
|
||||
keepAliveProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
|
||||
StateService serviceStub = new StateServiceStub(session, keepAliveProducer);
|
||||
|
||||
String localInboxDestination = dataDestination + "." + name;
|
||||
|
||||
ReplicatedLocalNode localNode = new ReplicatedLocalNode(name,localInboxDestination, serviceStub);
|
||||
Timer timer = new Timer();
|
||||
DefaultCluster answer = new DefaultCluster(localNode, dataDestination, groupDestination, connection, session, producer, timer, inactiveTime);
|
||||
return answer;
|
||||
}
|
||||
|
||||
/*
|
||||
protected Cluster createInternalCluster(Session session, Topic dataDestination) {
|
||||
MessageProducer producer = createProducer(session);
|
||||
return new DefaultCluster(new NonReplicatedLocalNode(), dataDestination, connection, session, producer);
|
||||
}
|
||||
*/
|
||||
|
||||
protected MessageProducer createProducer(Session session, Topic groupDestination) throws JMSException {
|
||||
return session.createProducer(groupDestination);
|
||||
}
|
||||
|
||||
protected Session createSession(Connection connection) throws JMSException {
|
||||
return connection.createSession(transacted, acknowledgeMode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.activecluster.Node;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of a remote Node
|
||||
*
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public class NodeImpl implements Node {
|
||||
private static final long serialVersionUID=-3909792803360045064L;
|
||||
private String name;
|
||||
private String destination;
|
||||
protected Map state;
|
||||
protected boolean coordinator;
|
||||
|
||||
/**
|
||||
* Allow a node to be copied for sending it as a message
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
public NodeImpl(Node node) {
|
||||
this(node.getName(),node.getDestination(), node.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Node
|
||||
* @param name
|
||||
* @param destination
|
||||
*/
|
||||
public NodeImpl(String name,String destination) {
|
||||
this(name,destination, new HashMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create A Node
|
||||
* @param name
|
||||
* @param destination
|
||||
* @param state
|
||||
*/
|
||||
public NodeImpl(String name,String destination, Map state) {
|
||||
this.name = name;
|
||||
this.destination = destination;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the node
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return pretty print of the node
|
||||
*/
|
||||
public String toString() {
|
||||
return "Node[<" + name + ">destination: " + destination + " state: " + state + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destination of the node
|
||||
*/
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the State
|
||||
* @return the State of the Node
|
||||
*/
|
||||
public synchronized Map getState() {
|
||||
return new HashMap(state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if this node has been elected as coordinator
|
||||
*/
|
||||
public boolean isCoordinator() {
|
||||
return coordinator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the zone
|
||||
* @return the Zone
|
||||
*/
|
||||
public Object getZone() {
|
||||
return state.get("zone");
|
||||
}
|
||||
|
||||
// Implementation methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
protected synchronized void setState(Map state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
protected void setCoordinator(boolean value) {
|
||||
coordinator = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import java.util.Map;
|
||||
import org.activecluster.LocalNode;
|
||||
|
||||
/**
|
||||
* Default implementation of a local Node which doesn't
|
||||
* have its state replicated
|
||||
*
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class NonReplicatedLocalNode extends NodeImpl implements LocalNode {
|
||||
private static final long serialVersionUID=2525565639637967143L;
|
||||
|
||||
/**
|
||||
* Create a Non-replicated local node
|
||||
* @param name
|
||||
* @param destination
|
||||
*/
|
||||
public NonReplicatedLocalNode(String name, String destination) {
|
||||
super(name,destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the local state
|
||||
* @param state
|
||||
*/
|
||||
public void setState(Map state) {
|
||||
super.setState(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shouldn't be called for non-replicated local nodes
|
||||
*/
|
||||
public void pingRemoteNodes() {
|
||||
throw new RuntimeException("Non-Replicated Local Node should not distribute it's state!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.jms.JMSException;
|
||||
import org.activecluster.LocalNode;
|
||||
import org.activecluster.Service;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of a local Node which has its
|
||||
* state replicated across the cluster
|
||||
*
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public class ReplicatedLocalNode extends NodeImpl implements LocalNode, Service {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID=4626381612145333540L;
|
||||
private StateService serviceStub;
|
||||
|
||||
/**
|
||||
* Create ReplicatedLocalNode
|
||||
* @param name
|
||||
* @param destination
|
||||
* @param serviceStub
|
||||
*/
|
||||
public ReplicatedLocalNode(String name,String destination, StateService serviceStub) {
|
||||
super(name,destination);
|
||||
this.serviceStub = serviceStub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the State of the local node
|
||||
* @param state
|
||||
*/
|
||||
public void setState(Map state) {
|
||||
super.setState(state);
|
||||
serviceStub.keepAlive(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* ping remote nodes
|
||||
*
|
||||
*/
|
||||
public void pingRemoteNodes() {
|
||||
serviceStub.keepAlive(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* start (lifecycle)
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void start() throws JMSException {
|
||||
}
|
||||
|
||||
/**
|
||||
* stop (lifecycle)
|
||||
* @throws JMSException
|
||||
*/
|
||||
public void stop() throws JMSException {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.activecluster.Node;
|
||||
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageListener;
|
||||
import javax.jms.ObjectMessage;
|
||||
|
||||
|
||||
/**
|
||||
* A JMS MessageListener which processes inbound messages and
|
||||
* applies them to a StateService
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class StateConsumer implements MessageListener {
|
||||
|
||||
private final static Log log = LogFactory.getLog(StateConsumer.class);
|
||||
|
||||
private StateService stateService;
|
||||
|
||||
public StateConsumer(StateService stateService) {
|
||||
if (stateService == null) {
|
||||
throw new IllegalArgumentException("Must specify a valid StateService implementation");
|
||||
}
|
||||
this.stateService = stateService;
|
||||
}
|
||||
|
||||
public void onMessage(Message message) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Received cluster data message!: " + message);
|
||||
}
|
||||
|
||||
if (message instanceof ObjectMessage) {
|
||||
ObjectMessage objectMessage = (ObjectMessage) message;
|
||||
try {
|
||||
Node node = (Node) objectMessage.getObject();
|
||||
String type = objectMessage.getJMSType();
|
||||
if (type != null && type.equals("shutdown")) {
|
||||
stateService.shutdown(node);
|
||||
}
|
||||
else {
|
||||
stateService.keepAlive(node);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Could not extract node from message: " + e + ". Message: " + message, e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Ignoring message: " + message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import org.activecluster.Node;
|
||||
|
||||
|
||||
/**
|
||||
* A client side proxy to the remove cluster
|
||||
*
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public interface StateService {
|
||||
|
||||
/**
|
||||
* Sends a keep alive to the cluster
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
public void keepAlive(Node node);
|
||||
|
||||
/**
|
||||
* Sends a shutdown message to the cluster
|
||||
*/
|
||||
public void shutdown(Node node);
|
||||
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.Map.Entry;
|
||||
import javax.jms.JMSException;
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.ClusterEvent;
|
||||
import org.activecluster.ClusterListener;
|
||||
import org.activecluster.Node;
|
||||
import org.activecluster.election.ElectionStrategy;
|
||||
import org.activecluster.election.impl.BullyElectionStrategy;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a node list
|
||||
*
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class StateServiceImpl implements StateService {
|
||||
|
||||
private final static Log log = LogFactory.getLog(StateServiceImpl.class);
|
||||
private Cluster cluster;
|
||||
private Object clusterLock;
|
||||
private Map nodes = new ConcurrentHashMap();
|
||||
private long inactiveTime;
|
||||
private List listeners = new CopyOnWriteArrayList();
|
||||
private String localDestination;
|
||||
private Runnable localNodePing;
|
||||
private NodeImpl coordinator;
|
||||
private ElectionStrategy electionStrategy;
|
||||
|
||||
/**
|
||||
* @param cluster
|
||||
* @param clusterLock
|
||||
* @param localNodePing
|
||||
* @param timer
|
||||
* @param inactiveTime
|
||||
*/
|
||||
/**
|
||||
* Constructor StateServiceImpl
|
||||
* @param cluster
|
||||
* @param clusterLock
|
||||
* @param localNodePing
|
||||
* @param timer
|
||||
* @param inactiveTime
|
||||
*/
|
||||
public StateServiceImpl(Cluster cluster, Object clusterLock, Runnable localNodePing, Timer timer, long inactiveTime) {
|
||||
this.cluster = cluster;
|
||||
this.clusterLock = clusterLock;
|
||||
this.localDestination = cluster.getLocalNode().getDestination();
|
||||
this.localNodePing = localNodePing;
|
||||
this.inactiveTime = inactiveTime;
|
||||
long delay = inactiveTime / 3;
|
||||
timer.scheduleAtFixedRate(createTimerTask(), delay, delay);
|
||||
(this.coordinator = (NodeImpl) cluster.getLocalNode()).setCoordinator(true);
|
||||
this.electionStrategy = new BullyElectionStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current election strategy
|
||||
*/
|
||||
public ElectionStrategy getElectionStrategy() {
|
||||
return electionStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the election strategy
|
||||
*
|
||||
* @param electionStrategy
|
||||
*/
|
||||
public void setElectionStrategy(ElectionStrategy electionStrategy) {
|
||||
this.electionStrategy = electionStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time of since last communication
|
||||
* @return length of time inactive
|
||||
*/
|
||||
public long getInactiveTime() {
|
||||
return inactiveTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time inactive
|
||||
* @param inactiveTime
|
||||
*/
|
||||
public void setInactiveTime(long inactiveTime) {
|
||||
this.inactiveTime = inactiveTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get A Map of nodes - where key = destination, value = node
|
||||
* @return map of destination/nodes
|
||||
*/
|
||||
public Map getNodes() {
|
||||
HashMap answer = new HashMap(nodes.size());
|
||||
for (Iterator iter = nodes.entrySet().iterator(); iter.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) iter.next();
|
||||
String key = entry.getKey().toString();
|
||||
NodeEntry nodeEntry = (NodeEntry) entry.getValue();
|
||||
answer.put(key, nodeEntry.node);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Got a keepalive
|
||||
* @param node
|
||||
*/
|
||||
public void keepAlive(Node node) {
|
||||
String key = node.getDestination();
|
||||
if (key != null && !localDestination.equals(key)) {
|
||||
NodeEntry entry = (NodeEntry) nodes.get(key);
|
||||
if (entry == null) {
|
||||
entry = new NodeEntry();
|
||||
entry.node = node;
|
||||
nodes.put(key, entry);
|
||||
nodeAdded(node);
|
||||
synchronized (clusterLock) {
|
||||
clusterLock.notifyAll();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// has the data changed
|
||||
if (stateHasChanged(entry.node, node)) {
|
||||
entry.node = node;
|
||||
nodeUpdated(node);
|
||||
}
|
||||
}
|
||||
|
||||
// lets update the timer at which the node will be considered
|
||||
// to be dead
|
||||
entry.lastKeepAlive = getTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown the node
|
||||
*/
|
||||
public void shutdown(Node node){
|
||||
String key=node.getDestination();
|
||||
if(key!=null){
|
||||
nodes.remove(key);
|
||||
ClusterEvent event=new ClusterEvent(cluster,node,ClusterEvent.ADD_NODE);
|
||||
for (Iterator i = listeners.iterator(); i.hasNext();){
|
||||
ClusterListener listener=(ClusterListener) i.next();
|
||||
listener.onNodeRemoved(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check nodes are alive
|
||||
*
|
||||
*/
|
||||
|
||||
public void checkForTimeouts() {
|
||||
localNodePing.run();
|
||||
long time = getTimeMillis();
|
||||
for (Iterator iter = nodes.entrySet().iterator(); iter.hasNext();) {
|
||||
Map.Entry entry = (Entry) iter.next();
|
||||
NodeEntry nodeEntry = (NodeEntry) entry.getValue();
|
||||
if (nodeEntry.lastKeepAlive + inactiveTime < time) {
|
||||
iter.remove();
|
||||
nodeFailed(nodeEntry.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TimerTask createTimerTask() {
|
||||
return new TimerTask() {
|
||||
public void run() {
|
||||
checkForTimeouts();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void addClusterListener(ClusterListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeClusterListener(ClusterListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void nodeAdded(Node node) {
|
||||
ClusterEvent event = new ClusterEvent(cluster, node, ClusterEvent.ADD_NODE);
|
||||
// lets take a copy to make contention easier
|
||||
Object[] array = listeners.toArray();
|
||||
for (int i = 0, size = array.length; i < size; i++) {
|
||||
ClusterListener listener = (ClusterListener) array[i];
|
||||
listener.onNodeAdd(event);
|
||||
}
|
||||
doElection();
|
||||
}
|
||||
|
||||
protected void nodeUpdated(Node node) {
|
||||
ClusterEvent event = new ClusterEvent(cluster, node, ClusterEvent.UPDATE_NODE);
|
||||
// lets take a copy to make contention easier
|
||||
Object[] array = listeners.toArray();
|
||||
for (int i = 0, size = array.length; i < size; i++) {
|
||||
ClusterListener listener = (ClusterListener) array[i];
|
||||
listener.onNodeUpdate(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected void nodeFailed(Node node) {
|
||||
ClusterEvent event = new ClusterEvent(cluster, node, ClusterEvent.REMOVE_NODE);
|
||||
// lets take a copy to make contention easier
|
||||
Object[] array = listeners.toArray();
|
||||
for (int i = 0, size = array.length; i < size; i++) {
|
||||
ClusterListener listener = (ClusterListener) array[i];
|
||||
listener.onNodeFailed(event);
|
||||
}
|
||||
doElection();
|
||||
}
|
||||
|
||||
protected void coordinatorChanged(Node node) {
|
||||
ClusterEvent event = new ClusterEvent(cluster, node, ClusterEvent.ELECTED_COORDINATOR);
|
||||
// lets take a copy to make contention easier
|
||||
Object[] array = listeners.toArray();
|
||||
for (int i = 0, size = array.length; i < size; i++) {
|
||||
ClusterListener listener = (ClusterListener) array[i];
|
||||
listener.onCoordinatorChanged(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doElection() {
|
||||
if (electionStrategy != null) {
|
||||
try {
|
||||
NodeImpl newElected = (NodeImpl) electionStrategy.doElection(cluster);
|
||||
if (newElected != null && !newElected.equals(coordinator)) {
|
||||
coordinator.setCoordinator(false);
|
||||
coordinator = newElected;
|
||||
coordinator.setCoordinator(true);
|
||||
coordinatorChanged(coordinator);
|
||||
}
|
||||
}
|
||||
catch (JMSException jmsEx) {
|
||||
log.error("do election failed", jmsEx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For performance we may wish to use a less granualar timing mechanism
|
||||
* only updating the time every x millis since we're only using
|
||||
* the time as a judge of when a node has not pinged for at least a few
|
||||
* hundred millis etc.
|
||||
*/
|
||||
protected long getTimeMillis() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
protected static class NodeEntry {
|
||||
public Node node;
|
||||
public long lastKeepAlive;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the node has changed state from the old in memory copy to the
|
||||
* newly arrived copy
|
||||
*/
|
||||
protected boolean stateHasChanged(Node oldNode, Node newNode) {
|
||||
Map oldState = oldNode.getState();
|
||||
Map newState = newNode.getState();
|
||||
if (oldState == newState) {
|
||||
return false;
|
||||
}
|
||||
return oldState == null || newState == null || !oldState.equals(newState);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.impl;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.activecluster.Node;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Session;
|
||||
|
||||
|
||||
/**
|
||||
* A local stub for the state service which sends JMS messages
|
||||
* to the cluster
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class StateServiceStub implements StateService {
|
||||
|
||||
private final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private Session session;
|
||||
private MessageProducer producer;
|
||||
|
||||
public StateServiceStub(Session session, MessageProducer producer) {
|
||||
this.session = session;
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
public void keepAlive(Node node) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Sending cluster data message: " + node);
|
||||
}
|
||||
|
||||
Message message = session.createObjectMessage(new NodeImpl(node));
|
||||
producer.send(message);
|
||||
}
|
||||
catch (JMSException e) {
|
||||
log.error("Could not send JMS message: " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown(Node node) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Sending shutdown message: " + node);
|
||||
}
|
||||
|
||||
Message message = session.createObjectMessage(new NodeImpl(node));
|
||||
message.setJMSType("shutdown");
|
||||
producer.send(message);
|
||||
}
|
||||
catch (JMSException e) {
|
||||
log.error("Could not send JMS message: " + e, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>
|
||||
Default implementation of ActiveCluster using standard JMS API to build the cluster.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>
|
||||
ActiveCluster API for working with a simple cluster abstraction for building cluster algorithms
|
||||
like buddy systems, voting, master/slave protocols, electing a controller and so forth.
|
||||
</p>
|
||||
Clusters communicate across a common destination (typically a Topic) but every member (node)of a
|
||||
cluster has a unique name (the generation of unique names is left to the developer), and a
|
||||
unique destination (which uses the unique name).
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.jms.JMSException;
|
||||
import org.activecluster.impl.ActiveMQClusterFactory;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class ChatDemo implements ClusterListener {
|
||||
private Cluster cluster;
|
||||
private String name = "unknown";
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
ChatDemo test = new ChatDemo();
|
||||
test.run();
|
||||
}
|
||||
catch (JMSException e) {
|
||||
System.out.println("Caught: " + e);
|
||||
e.printStackTrace();
|
||||
Exception c = e.getLinkedException();
|
||||
if (c != null) {
|
||||
System.out.println("Cause: " + c);
|
||||
c.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Caught: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
cluster = createCluster();
|
||||
cluster.addClusterListener(this);
|
||||
cluster.start();
|
||||
|
||||
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
System.out.println("Welcome to the ActiveCluster Chat Demo!");
|
||||
System.out.println();
|
||||
System.out.println("Enter text to talk or type");
|
||||
System.out.println(" /quit to terminate the application");
|
||||
System.out.println(" /name foo to change your name to be 'foo'");
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
boolean running = true;
|
||||
while (running) {
|
||||
String line = reader.readLine();
|
||||
if (line == null || line.trim().equalsIgnoreCase("quit")) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
running = processCommand(line.trim());
|
||||
}
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
protected boolean processCommand(String text) throws JMSException {
|
||||
if (text.equals("/quit")) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (text.startsWith("/name")) {
|
||||
name = text.substring(5).trim();
|
||||
System.out.println("* name now changed to: " + name);
|
||||
}
|
||||
else {
|
||||
// lets talk
|
||||
Map map = new HashMap();
|
||||
map.put("text", text);
|
||||
map.put("name", name);
|
||||
cluster.getLocalNode().setState(map);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onNodeAdd(ClusterEvent event) {
|
||||
System.out.println("* " + getName(event) + " has joined the room");
|
||||
}
|
||||
|
||||
public void onNodeUpdate(ClusterEvent event) {
|
||||
System.out.println(getName(event) + "> " + getText(event));
|
||||
}
|
||||
|
||||
public void onNodeRemoved(ClusterEvent event) {
|
||||
System.out.println("* " + getName(event) + " has left the room");
|
||||
}
|
||||
|
||||
public void onNodeFailed(ClusterEvent event) {
|
||||
System.out.println("* " + getName(event) + " has failed unexpectedly");
|
||||
}
|
||||
|
||||
public void onCoordinatorChanged(ClusterEvent event){
|
||||
|
||||
}
|
||||
|
||||
protected Object getName(ClusterEvent event) {
|
||||
return event.getNode().getState().get("name");
|
||||
}
|
||||
|
||||
protected Object getText(ClusterEvent event) {
|
||||
return event.getNode().getState().get("text");
|
||||
}
|
||||
|
||||
protected void stop() throws JMSException {
|
||||
cluster.stop();
|
||||
}
|
||||
|
||||
protected Cluster createCluster() throws JMSException, ClusterException {
|
||||
ClusterFactory factory = new ActiveMQClusterFactory();
|
||||
return factory.createCluster("ORG.CODEHAUS.ACTIVEMQ.TEST.CLUSTER");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import org.activecluster.impl.ActiveMQClusterFactory;
|
||||
import org.activecluster.impl.DefaultClusterFactory;
|
||||
import org.activecluster.election.ElectionStrategy;
|
||||
import org.activecluster.election.impl.BullyElectionStrategy;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class ClusterDemo {
|
||||
protected Cluster cluster;
|
||||
private String name;
|
||||
private ElectionStrategy electionStrategy;
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
ClusterDemo test = new ClusterDemo();
|
||||
if (args.length > 0) {
|
||||
test.name = args[0];
|
||||
}
|
||||
test.demo();
|
||||
}
|
||||
catch (JMSException e) {
|
||||
System.out.println("Caught: " + e);
|
||||
e.printStackTrace();
|
||||
Exception c = e.getLinkedException();
|
||||
if (c != null) {
|
||||
System.out.println("Cause: " + c);
|
||||
c.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Caught: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void demo() throws Exception {
|
||||
start();
|
||||
|
||||
cluster.addClusterListener(new TestingClusterListener(cluster));
|
||||
|
||||
System.out.println("Enter 'quit' to terminate");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null || line.trim().equalsIgnoreCase("quit")) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
Map map = new HashMap();
|
||||
map.put("text", line);
|
||||
cluster.getLocalNode().setState(map);
|
||||
}
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
protected void start() throws JMSException, ClusterException {
|
||||
cluster = createCluster();
|
||||
if (name != null) {
|
||||
System.out.println("Starting node: " + name);
|
||||
|
||||
// TODO could we do cluster.setName() ?
|
||||
Map state = new HashMap();
|
||||
state.put("name", name);
|
||||
cluster.getLocalNode().setState(state);
|
||||
}
|
||||
cluster.start();
|
||||
if (electionStrategy == null) {
|
||||
electionStrategy = new BullyElectionStrategy();
|
||||
}
|
||||
electionStrategy.doElection(cluster);
|
||||
}
|
||||
|
||||
protected void stop() throws JMSException {
|
||||
cluster.stop();
|
||||
}
|
||||
|
||||
protected Cluster createCluster() throws JMSException, ClusterException {
|
||||
ClusterFactory factory = new ActiveMQClusterFactory();
|
||||
return factory.createCluster("ORG.CODEHAUS.ACTIVEMQ.TEST.CLUSTER");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageListener;
|
||||
import javax.jms.ObjectMessage;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.ClusterEvent;
|
||||
import org.activecluster.ClusterListener;
|
||||
import org.activecluster.impl.DefaultClusterFactory;
|
||||
import org.activemq.ActiveMQConnectionFactory;
|
||||
|
||||
/**
|
||||
* Test ActiveCluster, ActiveMQ, with an eye to putting WADI on top of them.
|
||||
*
|
||||
* @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell </a>
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class ClusterFunctionTest extends TestCase {
|
||||
protected Log _log = LogFactory.getLog(ClusterFunctionTest.class);
|
||||
|
||||
public ClusterFunctionTest(String name) {
|
||||
super(name);
|
||||
}
|
||||
protected ActiveMQConnectionFactory _connectionFactory;
|
||||
protected Connection _connection;
|
||||
protected DefaultClusterFactory _clusterFactory;
|
||||
protected Cluster _cluster0;
|
||||
protected Cluster _cluster1;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
testResponsePassed = false;
|
||||
_connectionFactory = new ActiveMQConnectionFactory("peer://cluster?persistent=false");
|
||||
_clusterFactory = new DefaultClusterFactory(_connectionFactory);
|
||||
_cluster0 = _clusterFactory.createCluster("ORG.CODEHAUS.WADI.TEST.CLUSTER");
|
||||
_cluster1 = _clusterFactory.createCluster("ORG.CODEHAUS.WADI.TEST.CLUSTER");
|
||||
_cluster0.start();
|
||||
_log.info("started node0: " + _cluster0.getLocalNode().getDestination());
|
||||
_cluster1.start();
|
||||
_log.info("started node1: " + _cluster1.getLocalNode().getDestination());
|
||||
}
|
||||
|
||||
protected void tearDown() throws JMSException {
|
||||
// _cluster1.stop();
|
||||
_cluster1 = null;
|
||||
// _cluster0.stop();
|
||||
_cluster0 = null;
|
||||
_clusterFactory = null;
|
||||
// _connection.stop();
|
||||
_connection = null;
|
||||
// _connectionFactory.stop();
|
||||
}
|
||||
//----------------------------------------
|
||||
class MyClusterListener implements ClusterListener {
|
||||
public void onNodeAdd(ClusterEvent ce) {
|
||||
_log.info("node added: " + ce.getNode());
|
||||
}
|
||||
|
||||
public void onNodeFailed(ClusterEvent ce) {
|
||||
_log.info("node failed: " + ce.getNode());
|
||||
}
|
||||
|
||||
public void onNodeRemoved(ClusterEvent ce) {
|
||||
_log.info("node removed: " + ce.getNode());
|
||||
}
|
||||
|
||||
public void onNodeUpdate(ClusterEvent ce) {
|
||||
_log.info("node updated: " + ce.getNode());
|
||||
}
|
||||
|
||||
public void onCoordinatorChanged(ClusterEvent ce) {
|
||||
_log.info("coordinator changed: " + ce.getNode());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCluster() throws Exception {
|
||||
_cluster0.addClusterListener(new MyClusterListener());
|
||||
Map map = new HashMap();
|
||||
map.put("text", "testing123");
|
||||
_cluster0.getLocalNode().setState(map);
|
||||
_log.info("nodes: " + _cluster0.getNodes());
|
||||
Thread.sleep(10000);
|
||||
assertTrue(true);
|
||||
}
|
||||
/**
|
||||
* An invokable piece of work.
|
||||
*/
|
||||
static interface Invocation extends java.io.Serializable {
|
||||
public void invoke(Cluster cluster, ObjectMessage om);
|
||||
}
|
||||
/**
|
||||
* Listen for messages, if they contain Invocations, invoke() them.
|
||||
*/
|
||||
class InvocationListener implements MessageListener {
|
||||
protected Cluster _cluster;
|
||||
|
||||
public InvocationListener(Cluster cluster) {
|
||||
_cluster = cluster;
|
||||
}
|
||||
|
||||
public void onMessage(Message message) {
|
||||
_log.info("message received: " + message);
|
||||
ObjectMessage om = null;
|
||||
Object tmp = null;
|
||||
Invocation invocation = null;
|
||||
try {
|
||||
if (message instanceof ObjectMessage && (om = (ObjectMessage) message) != null
|
||||
&& (tmp = om.getObject()) != null && tmp instanceof Invocation
|
||||
&& (invocation = (Invocation) tmp) != null) {
|
||||
_log.info("invoking message on: " + _cluster.getLocalNode());
|
||||
invocation.invoke(_cluster, om);
|
||||
_log.info("message successfully invoked on: " + _cluster.getLocalNode());
|
||||
}
|
||||
else {
|
||||
_log.warn("bad message: " + message);
|
||||
}
|
||||
}
|
||||
catch (JMSException e) {
|
||||
_log.warn("unexpected problem", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A request for a piece of work which involves sending a response back to the original requester.
|
||||
*/
|
||||
static class Request implements Invocation {
|
||||
public void invoke(Cluster cluster, ObjectMessage om2) {
|
||||
try {
|
||||
System.out.println("request received");
|
||||
ObjectMessage om = cluster.createObjectMessage();
|
||||
om.setJMSReplyTo(cluster.createDestination(cluster.getLocalNode().getDestination()));
|
||||
om.setObject(new Response());
|
||||
System.out.println("sending response");
|
||||
cluster.send(om2.getJMSReplyTo(), om);
|
||||
System.out.println("request processed");
|
||||
}
|
||||
catch (JMSException e) {
|
||||
System.err.println("problem sending response");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
static boolean testResponsePassed = false;
|
||||
/**
|
||||
* A response containing a piece of work.
|
||||
*/
|
||||
static class Response implements Invocation {
|
||||
public void invoke(Cluster cluster, ObjectMessage om) {
|
||||
try {
|
||||
System.out.println("response arrived from: " + om.getJMSReplyTo());
|
||||
// set a flag to test later
|
||||
ClusterFunctionTest.testResponsePassed = true;
|
||||
System.out.println("response processed on: " + cluster.getLocalNode().getDestination());
|
||||
}
|
||||
catch (JMSException e) {
|
||||
System.err.println("problem processing response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testResponse() throws Exception {
|
||||
MessageListener listener0 = new InvocationListener(_cluster0);
|
||||
MessageListener listener1 = new InvocationListener(_cluster1);
|
||||
// 1->(n-1) messages (excludes self)
|
||||
_cluster0.createConsumer(_cluster0.getDestination(), null, true).setMessageListener(listener0);
|
||||
// 1->1 messages
|
||||
_cluster0.createConsumer(_cluster0.getLocalNode().getDestination()).setMessageListener(listener0);
|
||||
// 1->(n-1) messages (excludes self)
|
||||
_cluster1.createConsumer(_cluster1.getDestination(), null, true).setMessageListener(listener1);
|
||||
// 1->1 messages
|
||||
_cluster1.createConsumer(_cluster1.getLocalNode().getDestination()).setMessageListener(listener1);
|
||||
ObjectMessage om = _cluster0.createObjectMessage();
|
||||
om.setJMSReplyTo(_cluster0.createDestination(_cluster0.getLocalNode().getDestination()));
|
||||
om.setObject(new Request());
|
||||
testResponsePassed = false;
|
||||
_cluster0.send(_cluster0.getLocalNode().getDestination(), om);
|
||||
Thread.sleep(3000);
|
||||
assertTrue(testResponsePassed);
|
||||
_log.info("request/response between same node OK");
|
||||
testResponsePassed = false;
|
||||
_cluster0.send(_cluster1.getLocalNode().getDestination(), om);
|
||||
Thread.sleep(3000);
|
||||
assertTrue(testResponsePassed);
|
||||
_log.info("request/response between two different nodes OK");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.jms.Message;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class ClusterTest extends ClusterTestSupport {
|
||||
|
||||
protected int count = 2;
|
||||
|
||||
public void xtestCluster() throws Exception {
|
||||
cluster = createCluster();
|
||||
|
||||
subscribeToCluster();
|
||||
|
||||
cluster.start();
|
||||
|
||||
String destination = cluster.getDestination();
|
||||
Message message = cluster.createTextMessage("abcdef");
|
||||
cluster.send(destination, message);
|
||||
|
||||
//clusterListener.waitForMessageToArrive();
|
||||
Thread.sleep(5000);
|
||||
|
||||
List list = clusterListener.flushMessages();
|
||||
assertEquals("Should have received a message: " + list, 1, list.size());
|
||||
|
||||
System.out.println("Received message: " + list.get(0));
|
||||
}
|
||||
|
||||
|
||||
public void testMembershipCluster() throws Exception {
|
||||
Cluster[] clusters = new Cluster[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
Cluster cluster = createCluster("node:" + i);
|
||||
clusters[i] = cluster;
|
||||
if (i==0){
|
||||
cluster.addClusterListener(new TestingClusterListener(cluster));
|
||||
}
|
||||
cluster.start();
|
||||
System.out.println("started " + clusters[i].getLocalNode().getName());
|
||||
|
||||
}
|
||||
|
||||
System.out.println("waiting to complete ...");
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
Cluster cluster = clusters[i];
|
||||
String localName = cluster.getLocalNode().getName();
|
||||
boolean completed = cluster.waitForClusterToComplete(count - 1, 5000);
|
||||
assertTrue("Node: " + i + " with contents: " + dumpConnectedNodes(cluster.getNodes()), completed);
|
||||
|
||||
System.out.println(localName + " completed = " + completed + " nodes = "
|
||||
+ dumpConnectedNodes(cluster.getNodes()));
|
||||
}
|
||||
|
||||
assertClusterMembership(clusters);
|
||||
|
||||
// lets wait for a while to see if things fail
|
||||
Thread.sleep(10000L);
|
||||
|
||||
assertClusterMembership(clusters);
|
||||
|
||||
Cluster testCluster = clusters[0];
|
||||
LocalNode testNode = testCluster.getLocalNode();
|
||||
String key = "key";
|
||||
String value = "value";
|
||||
|
||||
Map map = testNode.getState();
|
||||
map.put(key, value);
|
||||
testNode.setState(map);
|
||||
|
||||
Thread.sleep(5000);
|
||||
for (int i = 1; i < count; i++) {
|
||||
Node node = (Node) clusters[i].getNodes().get(testNode.getDestination());
|
||||
assertTrue("The current test node should be in the cluster: " + i, node != null);
|
||||
assertTrue(node.getState().get(key).equals(value));
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
System.out.println(clusters[i].getLocalNode().getName() + " Is coordinator = " + clusters[i].getLocalNode().isCoordinator());
|
||||
clusters[i].stop();
|
||||
Thread.sleep(250);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertClusterMembership(Cluster[] clusters) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
System.out.println("Cluster: " + i + " = " + clusters[i].getNodes());
|
||||
|
||||
assertEquals("Size of clusters for cluster: " + i, count - 1, clusters[i].getNodes().size());
|
||||
System.out.println(clusters[i].getLocalNode().getName() + " Is coordinator = " + clusters[i].getLocalNode().isCoordinator());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import org.activecluster.impl.ActiveMQClusterFactory;
|
||||
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.Topic;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.3 $
|
||||
*/
|
||||
public abstract class ClusterTestSupport extends TestSupport {
|
||||
|
||||
protected Cluster cluster;
|
||||
protected StubMessageListener clusterListener = new StubMessageListener();
|
||||
protected StubMessageListener inboxListener = new StubMessageListener();
|
||||
private MessageConsumer clusterConsumer;
|
||||
private MessageConsumer inboxConsumer;
|
||||
|
||||
|
||||
protected void sendMessageToNode(Node node, String text) throws Exception {
|
||||
Message message = cluster.createTextMessage(text);
|
||||
cluster.send(node.getDestination(), message);
|
||||
}
|
||||
|
||||
protected void sendMessageToCluster(String text) throws Exception {
|
||||
Message message = cluster.createTextMessage(text);
|
||||
cluster.send(cluster.getDestination(), message);
|
||||
}
|
||||
|
||||
protected void subscribeToCluster() throws Exception {
|
||||
|
||||
// listen to cluster messages
|
||||
String clusterDestination = cluster.getDestination();
|
||||
assertTrue("Local destination must not be null", clusterDestination != null);
|
||||
clusterConsumer = cluster.createConsumer(clusterDestination);
|
||||
clusterConsumer.setMessageListener(clusterListener);
|
||||
|
||||
// listen to inbox messages (individual messages)
|
||||
String localDestination = cluster.getLocalNode().getDestination();
|
||||
assertTrue("Local destination must not be null", localDestination != null);
|
||||
|
||||
System.out.println("Consuming from local destination: " + localDestination);
|
||||
inboxConsumer = cluster.createConsumer(localDestination);
|
||||
inboxConsumer.setMessageListener(inboxListener);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
if (cluster != null) {
|
||||
cluster.stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A mock message listener for testing
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class StubMessageListener implements MessageListener {
|
||||
private List messages = new ArrayList();
|
||||
private Object semaphore;
|
||||
|
||||
public StubMessageListener() {
|
||||
this(new Object());
|
||||
}
|
||||
|
||||
public StubMessageListener(Object semaphore) {
|
||||
this.semaphore = semaphore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all the messages on the list so far, clearing the buffer
|
||||
*/
|
||||
public synchronized List flushMessages() {
|
||||
List answer = new ArrayList(messages);
|
||||
messages.clear();
|
||||
return answer;
|
||||
}
|
||||
|
||||
public synchronized void onMessage(Message message) {
|
||||
messages.add(message);
|
||||
synchronized (semaphore) {
|
||||
semaphore.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForMessageToArrive() {
|
||||
System.out.println("Waiting for message to arrive");
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
if (messages.isEmpty()) {
|
||||
synchronized (semaphore) {
|
||||
semaphore.wait(4000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
System.out.println("Caught: " + e);
|
||||
}
|
||||
long end = System.currentTimeMillis() - start;
|
||||
|
||||
System.out.println("End of wait for " + end + " millis");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.activecluster.impl.ActiveMQClusterFactory;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class TestSupport extends TestCase {
|
||||
protected String dumpConnectedNodes(Map nodes) {
|
||||
String result = "";
|
||||
for (Iterator i = nodes.values().iterator(); i.hasNext();) {
|
||||
|
||||
Object value = i.next();
|
||||
if (value instanceof Node) {
|
||||
Node node = (Node) value;
|
||||
result += node.getName() + ",";
|
||||
}
|
||||
else {
|
||||
System.out.println("Got node of type: " + value.getClass());
|
||||
result += value + ",";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Cluster createCluster() throws JMSException, ClusterException {
|
||||
ClusterFactory factory = new ActiveMQClusterFactory();
|
||||
return factory.createCluster("ORG.CODEHAUS.ACTIVEMQ.TEST.CLUSTER");
|
||||
}
|
||||
|
||||
protected Cluster createCluster(String name) throws JMSException, ClusterException {
|
||||
Cluster cluster = createCluster();
|
||||
return cluster;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster;
|
||||
|
||||
import org.activecluster.impl.DefaultCluster;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class TestingClusterListener implements ClusterListener {
|
||||
private Cluster cluster;
|
||||
|
||||
public TestingClusterListener(Cluster cluster){
|
||||
this.cluster = cluster;
|
||||
}
|
||||
public void onNodeAdd(ClusterEvent event) {
|
||||
printEvent("ADDED: ", event);
|
||||
}
|
||||
|
||||
public void onNodeUpdate(ClusterEvent event) {
|
||||
printEvent("UPDATED: ", event);
|
||||
}
|
||||
|
||||
public void onNodeRemoved(ClusterEvent event) {
|
||||
printEvent("REMOVED: ", event);
|
||||
}
|
||||
|
||||
public void onNodeFailed(ClusterEvent event) {
|
||||
printEvent("FAILED: ", event);
|
||||
}
|
||||
|
||||
public void onCoordinatorChanged(ClusterEvent event) {
|
||||
printEvent("COORDINATOR: ", event);
|
||||
}
|
||||
|
||||
protected void printEvent(String text, ClusterEvent event) {
|
||||
System.out.println(text + event.getNode());
|
||||
System.out.println("Current cluster is now: " + cluster.getNodes().keySet());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class BuddyGroupModelTest extends GroupTestSupport {
|
||||
|
||||
public void testGroups() throws Exception {
|
||||
addNode("a");
|
||||
|
||||
// lets check how many groups have been created
|
||||
List groups = model.getGroups();
|
||||
assertEquals("number of groups: " + groups, 1, model.getGroups().size());
|
||||
|
||||
Group group = (Group) model.getGroups().get(0);
|
||||
assertIncomplete(group);
|
||||
|
||||
addNode("b");
|
||||
assertEquals("number of groups: " + groups, 2, model.getGroups().size());
|
||||
|
||||
// lets see if the first node is now complete
|
||||
assertUsable(group);
|
||||
|
||||
group = (Group) model.getGroups().get(1);
|
||||
assertUsable(group);
|
||||
|
||||
|
||||
addNode("c");
|
||||
assertEquals("number of groups: " + groups, 3, model.getGroups().size());
|
||||
group = (Group) model.getGroups().get(2);
|
||||
assertUsable(group);
|
||||
|
||||
|
||||
addNode("d");
|
||||
assertEquals("number of groups: " + groups, 4, model.getGroups().size());
|
||||
group = (Group) model.getGroups().get(3);
|
||||
assertUsable(group);
|
||||
|
||||
}
|
||||
|
||||
public void testRemoveGroups() {
|
||||
String[] nodeNames = {"a", "b", "c"};
|
||||
addNodes(nodeNames);
|
||||
|
||||
// TODO now lets remove the nodes and check group states..
|
||||
}
|
||||
|
||||
protected GroupModel createGroupModel() {
|
||||
return new BuddyGroupModel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1.4 $
|
||||
*/
|
||||
public class GroupModelTest extends GroupTestSupport {
|
||||
|
||||
public void testGroups() throws Exception {
|
||||
addNode("a");
|
||||
|
||||
// lets check how many groups have been created
|
||||
List groups = model.getGroups();
|
||||
assertEquals("number of groups: " + groups, 1, model.getGroups().size());
|
||||
|
||||
Group group = (Group) model.getGroups().get(0);
|
||||
assertIncomplete(group);
|
||||
|
||||
addNode("b");
|
||||
assertNotFullButUsable(group);
|
||||
assertEquals("number of groups: " + groups, 1, model.getGroups().size());
|
||||
|
||||
addNode("c");
|
||||
assertFull(group);
|
||||
assertEquals("number of groups: " + groups, 1, model.getGroups().size());
|
||||
|
||||
|
||||
addNode("d");
|
||||
assertEquals("number of groups: " + groups, 2, model.getGroups().size());
|
||||
group = (Group) model.getGroups().get(1);
|
||||
assertIncomplete(group);
|
||||
}
|
||||
|
||||
public void testRemoveGroups() {
|
||||
String[] nodeNames = {"a", "b", "c"};
|
||||
addNodes(nodeNames);
|
||||
|
||||
// TODO now lets remove the nodes and check group states..
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 LogicBlaze, Inc. (http://www.logicblaze.com)
|
||||
*
|
||||
* Licensed 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.activecluster.group;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
import org.activecluster.Cluster;
|
||||
import org.activecluster.ClusterEvent;
|
||||
import org.activecluster.ClusterListener;
|
||||
import org.activecluster.Node;
|
||||
import org.activecluster.impl.NodeImpl;
|
||||
|
||||
/**
|
||||
* A base class for Group model testing
|
||||
*
|
||||
* @version $Revision: 1.5 $
|
||||
*/
|
||||
public abstract class GroupTestSupport extends TestCase {
|
||||
|
||||
protected GroupModel model;
|
||||
private ClusterListener listener;
|
||||
private Cluster cluster;
|
||||
private Map nodes = new HashMap();
|
||||
|
||||
protected void addNodes(String[] nodeNames) {
|
||||
for (int i = 0; i < nodeNames.length; i++) {
|
||||
String nodeName = nodeNames[i];
|
||||
addNode(nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addNode(String nodeName) {
|
||||
Node node = new NodeImpl(nodeName,nodeName);
|
||||
nodes.put(nodeName, node);
|
||||
listener.onNodeAdd(new ClusterEvent(cluster, node, ClusterEvent.ADD_NODE));
|
||||
}
|
||||
|
||||
protected void assertFull(Group group) {
|
||||
assertTrue("Group is not full and usable. Members: " + group.getMembers(), group.isFull() && group.isUsable());
|
||||
}
|
||||
|
||||
protected void assertNotFullButUsable(Group group) {
|
||||
assertTrue("Group is not not full but usable. Members: " + group.getMembers(), !group.isFull() && group.isUsable());
|
||||
}
|
||||
|
||||
protected void assertIncomplete(Group group) {
|
||||
assertTrue("Group is not not full or usable. Members: " + group.getMembers(), !group.isFull() && !group.isUsable());
|
||||
}
|
||||
|
||||
protected void assertUsable(Group group) {
|
||||
assertTrue("Group is not usable. Members: " + group.getMembers(), group.isUsable());
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
model = createGroupModel();
|
||||
listener = new GroupClusterListener(model);
|
||||
}
|
||||
|
||||
protected GroupModel createGroupModel() {
|
||||
return new GroupModel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project default="default" xmlns:j="jelly:core" xmlns:ant="jelly:ant">
|
||||
<goal name="default">
|
||||
<attainGoal name="jar:install"/>
|
||||
</goal>
|
||||
|
||||
<goal name="idl:compile">
|
||||
|
||||
<ant:taskdef name="java2idl" classname="org.openorb.compiler.taskdefs.Java2Idl">
|
||||
<ant:classpath refid="maven.dependency.classpath"/>
|
||||
</ant:taskdef>
|
||||
<ant:taskdef name="idl2java" classname="org.openorb.compiler.taskdefs.Idl2Java">
|
||||
<ant:classpath refid="maven.dependency.classpath"/>
|
||||
</ant:taskdef>
|
||||
|
||||
<j:set var="targetdir" value="${basedir}/target/test-iiop"/>
|
||||
<ant:mkdir dir="${targetdir}"/>
|
||||
|
||||
<idl2java cachefile="${targetdir}/java2idl.cache"
|
||||
includepath="${basedir}/target/test-classes"
|
||||
destdir="${basedir}/src/test"
|
||||
srcdir="${basedir}/target/test-classes"
|
||||
includeorbidl="false">
|
||||
<include name="org/activeio/oneport/TestIIOPServer.idl" />
|
||||
</idl2java>
|
||||
|
||||
<!--
|
||||
<ant:java2idl cachefile="${targetdir}/java2idl.cache"
|
||||
includes="org/activeio/oneport/TestIIOPServerImpl.class"
|
||||
destdir="${basedir}/src/test"
|
||||
generateidl="false"
|
||||
generatestub="true"
|
||||
generatetie="true">
|
||||
<ant:src path="${basedir}/target/test-classes"/>
|
||||
</ant:java2idl>
|
||||
-->
|
||||
|
||||
</goal>
|
||||
|
||||
<preGoal name="test:test">
|
||||
<j:choose>
|
||||
<j:when test="${context.getVariable('os.name').startsWith('Windows')}">
|
||||
<ant:copy todir=".">
|
||||
<ant:fileset dir="${maven.repo.local}/ibmaio/libs/win32" includes="*.dll"/>
|
||||
</ant:copy>
|
||||
</j:when>
|
||||
<j:when test="${context.getVariable('os.name').startsWith('Linux') and context.getVariable('os.version').startsWith('2.6.')}">
|
||||
<ant:copy todir=".">
|
||||
<ant:fileset dir="${maven.repo.local}/ibmaio/libs/linux32" includes="*.so"/>
|
||||
</ant:copy>
|
||||
<j:set var="maven.junit.jvmargs" value="${maven.junit.jvmargs} -Djava.library.path=."/>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<echo>Diabling IBM AIO tests since your platform (${context.getVariable('os.name')} ${context.getVariable('os.version')}) is not recognized</echo>
|
||||
<j:set var="maven.junit.jvmargs" value="${maven.junit.jvmargs} -Ddisable.aio.tests=true"/>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</preGoal>
|
||||
|
||||
<goal name="setclasspath">
|
||||
<path id="test.classpath">
|
||||
<pathelement path="${maven.build.dest}"/>
|
||||
<pathelement path="target/classes"/>
|
||||
<pathelement path="target/test-classes"/>
|
||||
<path refid="maven.dependency.classpath"/>
|
||||
</path>
|
||||
</goal>
|
||||
|
||||
<goal name="benchmark:client" prereqs="setclasspath"
|
||||
description="Runs the benchmark client load simulator">
|
||||
|
||||
<j:if test="${empty(url)}">
|
||||
<j:set var="url" value="socket://localhost:3434"/>
|
||||
</j:if>
|
||||
|
||||
<echo>Running the benchmark client load simulator</echo>
|
||||
<java classname="org.activeio.net.benchmark.ClientLoadSimulator" fork="yes" maxmemory="100M">
|
||||
<classpath refid="test.classpath"/>
|
||||
<sysproperty key="org.activeio.net.nio.BufferSize" value="10240"/>
|
||||
|
||||
<arg value="-url"/>
|
||||
<arg value="${url}"/>
|
||||
|
||||
<j:if test="${!empty(concurrentClients)}">
|
||||
<arg value="-concurrentClients"/>
|
||||
<arg value="${concurrentClients}"/>
|
||||
</j:if>
|
||||
<j:if test="${!empty(rampUpTime)}">
|
||||
<arg value="-rampUpTime"/>
|
||||
<arg value="${rampUpTime}"/>
|
||||
</j:if>
|
||||
<j:if test="${!empty(requestDelay)}">
|
||||
<arg value="-requestDelay"/>
|
||||
<arg value="${requestDelay}"/>
|
||||
</j:if>
|
||||
<j:if test="${!empty(requestIterations)}">
|
||||
<arg value="-requestIterations"/>
|
||||
<arg value="${requestIterations}"/>
|
||||
</j:if>
|
||||
<j:if test="${!empty(requestSize)}">
|
||||
<arg value="-requestSize"/>
|
||||
<arg value="${requestSize}"/>
|
||||
</j:if>
|
||||
<j:if test="${!empty(sampleInterval)}">
|
||||
<arg value="-sampleInterval"/>
|
||||
<arg value="${sampleInterval}"/>
|
||||
</j:if>
|
||||
|
||||
</java>
|
||||
|
||||
</goal>
|
||||
|
||||
<goal name="benchmark:server" prereqs="setclasspath"
|
||||
description="Runs the benchmark server">
|
||||
|
||||
<j:if test="${empty(url)}">
|
||||
<j:set var="url" value="socket://localhost:3434"/>
|
||||
</j:if>
|
||||
|
||||
<echo>Running the benchmark server</echo>
|
||||
<java classname="org.activeio.net.benchmark.Server" fork="yes" maxmemory="100M">
|
||||
<classpath refid="test.classpath"/>
|
||||
|
||||
<arg value="-url"/>
|
||||
<arg value="${url}"/>
|
||||
|
||||
<j:if test="${!empty(requestDelay)}">
|
||||
<arg value="-requestDelay"/>
|
||||
<arg value="${requestDelay}"/>
|
||||
</j:if>
|
||||
<j:if test="${!empty(sampleInterval)}">
|
||||
<arg value="-sampleInterval"/>
|
||||
<arg value="${sampleInterval}"/>
|
||||
</j:if>
|
||||
|
||||
</java>
|
||||
|
||||
</goal>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,68 @@
|
|||
maven.repo.remote=http://tranql.codehaus.org/maven,http://www.openejb.org/maven,http://www.ibiblio.org/maven
|
||||
|
||||
maven.eclipse.classpath.include=src/resources
|
||||
|
||||
maven.compile.source=1.4
|
||||
maven.compile.target=1.4
|
||||
|
||||
maven.compile.deprecation=true
|
||||
maven.compile.debug=true
|
||||
maven.compile.optimize=true
|
||||
|
||||
#maven.junit.fork=false
|
||||
maven.junit.fork=true
|
||||
maven.javadoc.source=1.4
|
||||
|
||||
maven.javadoc.links=\
|
||||
http://java.sun.com/j2se/1.4.1/docs/api/,\
|
||||
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent,\
|
||||
http://jakarta.apache.org/commons/logging/apidocs
|
||||
|
||||
maven.xdoc.theme.url=http://codehaus.org/codehaus-style.css
|
||||
|
||||
maven.artifact.legacy=true
|
||||
maven.repo.central=dist.codehaus.org
|
||||
maven.repo.central.directory=/dist
|
||||
maven.remote.group=activeio
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# IDE options
|
||||
# -------------------------------------------------------------------
|
||||
#maven.eclipse.classpath.include=target/test-iiop/classes
|
||||
#maven.idea.generated.source=test-iiop/classes
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# dependency versions
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# What is used.
|
||||
concurrent_version=1.3.4
|
||||
howl_logger_version=0.1.8
|
||||
ibmaio_version=1.0
|
||||
|
||||
openorb_orb_version=1.4.0-GERONIMO
|
||||
openorb_tools_version=1.4.0-GERONIMO
|
||||
openorb_orb_tools_version=1.4.0-GERONIMO
|
||||
openorb_orb_omg_version=1.4.0-GERONIMO
|
||||
|
||||
avalon_framework_version=4.1.4
|
||||
commons_cli_version=1.0
|
||||
avalon_logkit_version=1.2.2
|
||||
|
||||
org.mortbay.jetty_version=5.1.2-SNAPSHOT
|
||||
p2psockets_core_version=1.1.2
|
||||
jxta_version=2.0
|
||||
|
||||
# For testing
|
||||
junit_version=3.8.1
|
||||
geronimo_spec_j2ee_version=1.4-rc4
|
||||
activemq_core_version=2.0
|
||||
commons_beanutils_version=1.6.1
|
||||
commons_collections_version=2.1
|
||||
|
||||
commons_logging_version=1.0.3
|
||||
log4j_version=1.2.8
|
||||
mx4j_version=3.0.1
|
||||
geronimo_version=1.0-SNAPSHOT
|
||||
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE project>
|
||||
<!--
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.
|
||||
-->
|
||||
<project>
|
||||
|
||||
<pomVersion>3</pomVersion>
|
||||
<id>activeio</id>
|
||||
<name>ActiveIO</name>
|
||||
<currentVersion>2.2-SNAPSHOT</currentVersion>
|
||||
<organization>
|
||||
<name>The ActiveIO Project</name>
|
||||
<url>http://activeio.org</url>
|
||||
<logo>http://activeio.org/activeio-logo.png</logo>
|
||||
</organization>
|
||||
|
||||
<package>org.activeio</package>
|
||||
<packageGroups>
|
||||
<packageGroup>
|
||||
<title>Protocol Implementation Framework</title>
|
||||
<packages>org.activeio.protocol.*</packages>
|
||||
</packageGroup>
|
||||
</packageGroups>
|
||||
|
||||
|
||||
<shortDescription>ActiveIO provides a high performance IO framework for implementing protocols.</shortDescription>
|
||||
<logo>/images/activeio-logo.png</logo>
|
||||
|
||||
<description></description>
|
||||
<url>http://activeio.org/</url>
|
||||
|
||||
<siteAddress>www.activeio.org</siteAddress>
|
||||
<siteDirectory>/home/projects/activeio/public_html/maven</siteDirectory>
|
||||
<distributionSite>dist.codehaus.org</distributionSite>
|
||||
<distributionDirectory>/dist</distributionDirectory>
|
||||
|
||||
<repository>
|
||||
<connection>scm:svn:https://svn.codehaus.org/activeio/trunk/activeio</connection>
|
||||
<developerConnection>scm:svn:svn+ssh://svn.activeio.org/home/projects/activeio/scm/trunk/activeio</developerConnection>
|
||||
<url>http://svn.activeio.org/viewcvs.cgi/activeio/</url>
|
||||
</repository>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>activeio dev</name>
|
||||
<subscribe>dev-subscribe@activeio.codehaus.org</subscribe>
|
||||
<unsubscribe>dev-unsubscribe@activeio.codehaus.org</unsubscribe>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>activeio users</name>
|
||||
<subscribe>user-subscribe@activeio.codehaus.org</subscribe>
|
||||
<unsubscribe>user-unsubscribe@activeio.codehaus.org</unsubscribe>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>activeio svn messages</name>
|
||||
<subscribe>scm-subscribe@activeio.codehaus.org</subscribe>
|
||||
<unsubscribe>scm-unsubscribe@activeio.codehaus.org</unsubscribe>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Hiram Chirino</name>
|
||||
<id>chirino</id>
|
||||
<email>hiram@hiramchirino.com</email>
|
||||
<organization></organization>
|
||||
<roles>
|
||||
<role>Founder</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Alan D. Cabrera</name>
|
||||
<id>adc</id>
|
||||
<email>adc@toolazydogs.com</email>
|
||||
<organization></organization>
|
||||
<roles>
|
||||
<role>Founder</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>David Blevins</name>
|
||||
<id>dblevins</id>
|
||||
<email>dblevins@gluecode.com</email>
|
||||
<organization></organization>
|
||||
<roles>
|
||||
<role>Founder</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<dependencies>
|
||||
<!-- Required Dependencies -->
|
||||
<dependency>
|
||||
<groupId>backport-util-concurrent</groupId>
|
||||
<artifactId>backport-util-concurrent</artifactId>
|
||||
<version>2.0_01_pd</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>concurrent</groupId>
|
||||
<artifactId>concurrent</artifactId>
|
||||
<version>${concurrent_version}</version>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- Optional Dependencies -->
|
||||
|
||||
<!-- For HOWL integration -->
|
||||
<dependency>
|
||||
<groupId>howl</groupId>
|
||||
<artifactId>howl-logger</artifactId>
|
||||
<version>${howl_logger_version}</version>
|
||||
<url>http://forge.objectweb.org/projects/howl</url>
|
||||
</dependency>
|
||||
|
||||
<!-- For JXTA integration -->
|
||||
<dependency>
|
||||
<groupId>p2psockets</groupId>
|
||||
<artifactId>p2psockets-core</artifactId>
|
||||
<version>${p2psockets_core_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jxta</groupId>
|
||||
<artifactId>jxta</artifactId>
|
||||
<version>${jxta_version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ibmaio</groupId>
|
||||
<artifactId>ibmaio</artifactId>
|
||||
<version>${ibmaio_version}</version>
|
||||
<url>https://www7b.software.ibm.com/dl/AW-0H8/AW-0H8-p</url>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- For Jetty integration -->
|
||||
<dependency>
|
||||
<groupId>jetty</groupId>
|
||||
<artifactId>org.mortbay.jetty</artifactId>
|
||||
<version>${org.mortbay.jetty_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- For OpenORB integration -->
|
||||
<dependency>
|
||||
<groupId>openorb</groupId>
|
||||
<artifactId>openorb-orb</artifactId>
|
||||
<version>${openorb_orb_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>openorb</groupId>
|
||||
<artifactId>openorb-tools</artifactId>
|
||||
<version>${openorb_tools_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>openorb</groupId>
|
||||
<artifactId>openorb-orb-tools</artifactId>
|
||||
<version>${openorb_orb_tools_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>openorb</groupId>
|
||||
<artifactId>openorb-orb-omg</artifactId>
|
||||
<version>${openorb_orb_omg_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>avalon</groupId>
|
||||
<artifactId>avalon-framework</artifactId>
|
||||
<version>${avalon_framework_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>avalon</groupId>
|
||||
<artifactId>avalon-logkit</artifactId>
|
||||
<version>${avalon_logkit_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Unit Test Dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>${commons_logging_version}</version>
|
||||
<url>http://jakarta.apache.org/commons/logging/</url>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>${log4j_version}</version>
|
||||
<url>http://jakarta.apache.org/log4j</url>
|
||||
</dependency>
|
||||
|
||||
<!-- Used by journal performance testing tools -->
|
||||
<dependency>
|
||||
<groupId>geronimo-spec</groupId>
|
||||
<artifactId>geronimo-spec-j2ee</artifactId>
|
||||
<version>${geronimo_spec_j2ee_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Used in testing -->
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>${commons_beanutils_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>${commons_collections_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Used by xnet GBean code -->
|
||||
<dependency>
|
||||
<groupId>geronimo</groupId>
|
||||
<artifactId>geronimo-kernel</artifactId>
|
||||
<version>${geronimo_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>geronimo</groupId>
|
||||
<artifactId>geronimo-j2ee</artifactId>
|
||||
<version>${geronimo_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mx4j</groupId>
|
||||
<artifactId>mx4j</artifactId>
|
||||
<version>${mx4j_version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!-- How we build the project -->
|
||||
<build>
|
||||
<sourceDirectory>src/java</sourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/resources</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<unitTestSourceDirectory>src/test</unitTestSourceDirectory>
|
||||
<unitTest>
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/test</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</unitTest>
|
||||
</build>
|
||||
|
||||
<reports>
|
||||
<report>maven-license-plugin</report>
|
||||
<report>maven-pmd-plugin</report>
|
||||
<report>maven-jdepend-plugin</report>
|
||||
<report>maven-jxr-plugin</report>
|
||||
<report>maven-javadoc-plugin</report>
|
||||
<report>maven-junit-report-plugin</report>
|
||||
<report>maven-faq-plugin</report>
|
||||
<report>maven-changes-plugin</report>
|
||||
<!--
|
||||
<report>maven-file-activity-plugin</report>
|
||||
<report>maven-developer-activity-plugin</report>
|
||||
<report>maven-changelog-plugin</report>
|
||||
<report>maven-statcvs-plugin</report>
|
||||
-->
|
||||
<report>maven-checkstyle-plugin</report>
|
||||
<report>maven-simian-plugin</report>
|
||||
<report>maven-clover-plugin</report>
|
||||
</reports>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* An AcceptListener object is used to receive accepted {@see org.activeio.Channel} connections.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface AcceptListener {
|
||||
|
||||
/**
|
||||
* A {@see AsyncChannelServer} will call this method to when a new channel connection has been
|
||||
* accepted.
|
||||
*
|
||||
* @param channel
|
||||
*/
|
||||
void onAccept(Channel channel);
|
||||
|
||||
/**
|
||||
* A {@see AsyncChannelServer} will call this method when a async failure occurs when accepting
|
||||
* a connection.
|
||||
*
|
||||
* @param error the exception that describes the failure.
|
||||
*/
|
||||
void onAcceptError(IOException error);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
|
||||
/**
|
||||
* Provides an Adaptable interface inspired by eclipse's IAdaptable class. Highly used in ActiveIO since Channel and Packet
|
||||
* implementations may be layered and application code may want request the higher level layers/abstractions to adapt to give access
|
||||
* to the lower layer implementation details.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Adaptable {
|
||||
|
||||
/**
|
||||
* @Return object that is an instance of requested type and is associated this this object. May return null if no
|
||||
* object of that type is associated.
|
||||
*/
|
||||
Object getAdapter(Class target);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* AsyncChannel objects asynchronously push 'up' {@see org.activeio.Packet} objects
|
||||
* to a registered {@see org.activeio.ChannelConsumer}.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface AsyncChannel extends InputAsyncChannel, OutputChannel {
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
/**
|
||||
* AsyncChannelFactory objects can create {@see org.activeio.AsyncChannel}
|
||||
* and {@see org.activeio.AsyncChannelServer} objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface AsyncChannelFactory {
|
||||
|
||||
/**
|
||||
* Opens a connection to server.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public AsyncChannel openAsyncChannel(URI location) throws IOException;
|
||||
|
||||
/**
|
||||
* Binds a server at the URI location.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public AsyncChannelServer bindAsyncChannel(URI location) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* A ChannelConsumer object is used to receive 'up' {@see org.activeio.Packet} objects.
|
||||
*
|
||||
* TODO: describe the threading model so that the implementor of this interface can know if
|
||||
* the methods in this interface can block for a long time or not. I'm thinking that it would
|
||||
* be best if these methods are not allowed to block for a long time to encourage SEDA style
|
||||
* processing.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface AsyncChannelListener {
|
||||
|
||||
/**
|
||||
* A {@see AsyncChannel} will call this method to deliver an 'up' packet to a consumer.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
void onPacket(Packet packet);
|
||||
|
||||
/**
|
||||
* A {@see AsyncChannel} will call this method when a async failure occurs in the channel.
|
||||
*
|
||||
* @param error the exception that describes the failure.
|
||||
*/
|
||||
void onPacketError(IOException error);
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
|
||||
/**
|
||||
* AsyncChannelServer objects asynchronously accept and create {@see org.activeio.Channel} objects
|
||||
* and then delivers those objects to a {@see org.activeio.AcceptConsumer}.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface AsyncChannelServer extends ChannelServer {
|
||||
|
||||
/**
|
||||
* Registers an AcceptListener which is notified of accepted channels.
|
||||
*
|
||||
* @param acceptListener
|
||||
*/
|
||||
void setAcceptListener(AcceptListener acceptListener);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 the original author or authors.
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* @deprecated Use AsyncChannel instead. This class will be removed very soon.
|
||||
*/
|
||||
public interface AsynchChannel extends AsyncChannel{
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 the original author or authors.
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* @deprecated Use AsyncChannelListener instead. This class will be removed very soon.
|
||||
*/
|
||||
public interface AsynchChannelListener extends AsyncChannelListener {
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2005 the original author or authors.
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* @deprecated Use AsyncChannelServer instead. This class will be removed very soon.
|
||||
*/
|
||||
public interface AsynchChannelServer extends AsyncChannelServer {
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package org.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Very similar to the java.io.ByteArrayInputStream but this version
|
||||
* is not thread safe.
|
||||
*/
|
||||
public class ByteArrayInputStream extends InputStream {
|
||||
|
||||
byte buffer[];
|
||||
int limit;
|
||||
int pos;
|
||||
int mark;
|
||||
|
||||
public ByteArrayInputStream(byte data[]) {
|
||||
this(data, 0, data.length);
|
||||
}
|
||||
|
||||
public ByteArrayInputStream(ByteSequence sequence) {
|
||||
this(sequence.getData(), sequence.getOffset(), sequence.getLength());
|
||||
}
|
||||
|
||||
public ByteArrayInputStream(byte data[], int offset, int size) {
|
||||
this.buffer = data;
|
||||
this.mark= this.pos = offset;
|
||||
this.limit = offset+size;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if( pos < limit )
|
||||
return buffer[pos++] & 0xff;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) {
|
||||
if (pos < limit) {
|
||||
len = Math.min(len, limit-pos);
|
||||
if (len > 0) {
|
||||
System.arraycopy(buffer, pos, b, off, len);
|
||||
pos += len;
|
||||
}
|
||||
return len;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public long skip(long len) throws IOException {
|
||||
if (pos < limit) {
|
||||
len = Math.min(len, limit-pos);
|
||||
if (len > 0) {
|
||||
pos += len;
|
||||
}
|
||||
return len;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return limit - pos;
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void mark(int markpos) {
|
||||
mark = pos;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
pos = mark;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package org.activeio;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Very similar to the java.io.ByteArrayOutputStream but this version
|
||||
* is not thread safe and the resulting data is returned in a ByteSequence
|
||||
* to avoid an extra byte[] allocation.
|
||||
*/
|
||||
public class ByteArrayOutputStream extends OutputStream {
|
||||
|
||||
byte buffer[];
|
||||
int size;
|
||||
|
||||
public ByteArrayOutputStream() {
|
||||
this(512);
|
||||
}
|
||||
public ByteArrayOutputStream(int capacity) {
|
||||
buffer = new byte[capacity];
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
int newsize = size + 1;
|
||||
checkCapacity(newsize);
|
||||
buffer[size] = (byte) b;
|
||||
size = newsize;
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) {
|
||||
int newsize = size + len;
|
||||
checkCapacity(newsize);
|
||||
System.arraycopy(b, off, buffer, size, len);
|
||||
size = newsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the the buffer has at least the minimumCapacity specified.
|
||||
* @param i
|
||||
*/
|
||||
private void checkCapacity(int minimumCapacity) {
|
||||
if (minimumCapacity > buffer.length) {
|
||||
byte b[] = new byte[Math.max(buffer.length << 1, minimumCapacity)];
|
||||
System.arraycopy(buffer, 0, b, 0, size);
|
||||
buffer = b;
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public ByteSequence toByteSequence() {
|
||||
return new ByteSequence(buffer, 0, size);
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
byte rc[] = new byte[size];
|
||||
System.arraycopy(buffer, 0, rc, 0, size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* <a href="http://activemq.org">ActiveMQ: The Open Source Message Fabric</a>
|
||||
*
|
||||
* Copyright 2005 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
public class ByteSequence {
|
||||
final byte[] data;
|
||||
final int offset;
|
||||
final int length;
|
||||
|
||||
public ByteSequence(byte data[], int offset, int length) {
|
||||
this.data = data;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
|
||||
/**
|
||||
* A Channel provides a standard procedure for regulating data transmission between
|
||||
* applications.
|
||||
*
|
||||
* The activeio API encourages that layered wire protocols be created by wiring
|
||||
* together a chain of Channel objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Channel extends Disposable, Service, Adaptable {
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Protique Ltd
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.Executor;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.SynchronousQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.activeio.adapter.AsyncToSyncChannelFactory;
|
||||
import org.activeio.adapter.SyncToAsyncChannelFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A {@see ChannelFactory}uses the requested URI's scheme to determine the
|
||||
* actual {@see org.activeio.SynchChannelFactory}or
|
||||
* {@see org.activeio.AsyncChannelFactory}implementation to use to create it's
|
||||
* {@see org.activeio.Channel}s and {@see org.activeio.ChannelServer}s.
|
||||
*
|
||||
* Each URI scheme that {@see ChannelFactory}object handles will have a
|
||||
* properties file located at: "META-INF/org.activeio.ChannelFactory/{scheme}".
|
||||
*
|
||||
*/
|
||||
public class ChannelFactory implements SyncChannelFactory, AsyncChannelFactory {
|
||||
|
||||
private final HashMap syncChannelFactoryMap = new HashMap();
|
||||
private final HashMap asyncChannelFactoryMap = new HashMap();
|
||||
|
||||
|
||||
static public final Executor DEFAULT_EXECUTOR = new ThreadPoolExecutor(10, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new SynchronousQueue());
|
||||
static {
|
||||
((ThreadPoolExecutor) DEFAULT_EXECUTOR).setThreadFactory(new ThreadFactory() {
|
||||
public Thread newThread(Runnable run) {
|
||||
Thread thread = new Thread(run);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static FactoryFinder finder = new FactoryFinder("META-INF/org.activeio.ChannelFactory/");
|
||||
|
||||
public SyncChannel openSyncChannel(URI location) throws IOException {
|
||||
SyncChannelFactory factory = getSynchChannelFactory(location.getScheme());
|
||||
return factory.openSyncChannel(location);
|
||||
}
|
||||
|
||||
public SyncChannelServer bindSyncChannel(URI location) throws IOException {
|
||||
SyncChannelFactory factory = getSynchChannelFactory(location.getScheme());
|
||||
return factory.bindSyncChannel(location);
|
||||
}
|
||||
|
||||
public AsyncChannel openAsyncChannel(URI location) throws IOException {
|
||||
AsyncChannelFactory factory = getAsyncChannelFactory(location.getScheme());
|
||||
return factory.openAsyncChannel(location);
|
||||
}
|
||||
|
||||
public AsyncChannelServer bindAsyncChannel(URI location) throws IOException {
|
||||
AsyncChannelFactory factory = getAsyncChannelFactory(location.getScheme());
|
||||
return factory.bindAsyncChannel(location);
|
||||
}
|
||||
|
||||
private SyncChannelFactory getSynchChannelFactory(String protocol) throws IOException {
|
||||
try {
|
||||
SyncChannelFactory rc = (SyncChannelFactory) syncChannelFactoryMap.get(protocol);
|
||||
if (rc == null) {
|
||||
try {
|
||||
rc = (SyncChannelFactory) finder.newInstance(protocol, "SyncChannelFactory.");
|
||||
} catch (Throwable original) {
|
||||
// try to recovery by using AsyncChannelFactory and adapt
|
||||
// it to be sync.
|
||||
try {
|
||||
AsyncChannelFactory f = (AsyncChannelFactory) finder.newInstance(protocol,
|
||||
"AsyncChannelFactory.");
|
||||
rc = AsyncToSyncChannelFactory.adapt(f);
|
||||
} catch (Throwable e) {
|
||||
// Recovery strategy failed.. throw original exception.
|
||||
throw original;
|
||||
}
|
||||
}
|
||||
syncChannelFactoryMap.put(protocol, rc);
|
||||
}
|
||||
return rc;
|
||||
} catch (Throwable e) {
|
||||
throw (IOException) new IOException("Could not load a SyncChannelFactory for protcol: " + protocol
|
||||
+ ", reason: " + e).initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
private AsyncChannelFactory getAsyncChannelFactory(String protocol) throws IOException {
|
||||
try {
|
||||
AsyncChannelFactory rc = (AsyncChannelFactory) asyncChannelFactoryMap.get(protocol);
|
||||
if (rc == null) {
|
||||
|
||||
try {
|
||||
rc = (AsyncChannelFactory) finder.newInstance(protocol, "AsyncChannelFactory.");
|
||||
} catch (Throwable original) {
|
||||
// try to recovery by using SynchChannelFactory and adapt it
|
||||
// to be async.
|
||||
try {
|
||||
SyncChannelFactory f = (SyncChannelFactory) finder.newInstance(protocol,
|
||||
"SyncChannelFactory.");
|
||||
rc = SyncToAsyncChannelFactory.adapt(f);
|
||||
} catch (Throwable e) {
|
||||
// Recovery strategy failed.. throw original exception.
|
||||
throw original;
|
||||
}
|
||||
}
|
||||
|
||||
asyncChannelFactoryMap.put(protocol, rc);
|
||||
}
|
||||
return rc;
|
||||
} catch (Throwable e) {
|
||||
throw (IOException) new IOException("Could not load a AsyncChannelFactory for protcol: " + protocol
|
||||
+ ", reason: " + e).initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* A ChannelServer is used to accept incoming requests to establish new Channel sessions.
|
||||
*
|
||||
* Like a normal {@see org.activeio.Channel}, A ChannelServer comes in two falvors, either:
|
||||
* {@see org.activeio.AsyncChannelServer} or
|
||||
* {@see org.activeio.SynchChannelServer}.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface ChannelServer extends Channel {
|
||||
|
||||
/**
|
||||
* The URI that was used when the channel was bound. This could be different
|
||||
* than what is used by a client to connect to the ChannelServer. For example,
|
||||
* the bind URI might be tcp://localhost:0 which means the channel should bind to
|
||||
* an anonymous port.
|
||||
*
|
||||
* @return The URI that was used when the channel was bound
|
||||
*/
|
||||
public URI getBindURI();
|
||||
|
||||
/**
|
||||
* Once bound, the channel may be able to construct a URI that is more sutible for when
|
||||
* a client needs to connect to the server. For examle the port of the URI may be
|
||||
* updated to reflect the actual local port that the channel server is listening on.
|
||||
*
|
||||
* @return a URI that a client can use to connect to the server or null if the channel cannot construct the URI.
|
||||
*/
|
||||
public URI getConnectURI();
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* The Disposable interface is implemented by objects the aquire resources whoes life cycle must be
|
||||
* managed. Once a Disposable has been disposed, it cannot be un-disposed.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Disposable {
|
||||
|
||||
/**
|
||||
* This method should not throw any exceptions. Cleaning up a Disposable object
|
||||
* should be easy of an end user therefore do not make him have to handle an Exception.
|
||||
*/
|
||||
void dispose();
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.activeio;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public class FactoryFinder {
|
||||
|
||||
private final String path;
|
||||
private final ConcurrentHashMap classMap = new ConcurrentHashMap();
|
||||
|
||||
public FactoryFinder(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the given key
|
||||
*
|
||||
* @param key is the key to add to the path to find a text file
|
||||
* containing the factory name
|
||||
* @return a newly created instance
|
||||
*/
|
||||
public Object newInstance(String key)
|
||||
throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException
|
||||
{
|
||||
return newInstance(key, null);
|
||||
}
|
||||
|
||||
public Object newInstance(String key, String propertyPrefix)
|
||||
throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException
|
||||
{
|
||||
if (propertyPrefix == null)
|
||||
propertyPrefix = "";
|
||||
|
||||
Class clazz = (Class) classMap.get(propertyPrefix + key);
|
||||
if (clazz == null) {
|
||||
clazz = newInstance(doFindFactoryProperies(key), propertyPrefix);
|
||||
classMap.put(propertyPrefix + key, clazz);
|
||||
}
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
private Class newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException, IOException {
|
||||
|
||||
String className = properties.getProperty(propertyPrefix + "class");
|
||||
if (className == null) {
|
||||
throw new IOException("Expected property is missing: " + propertyPrefix + "class");
|
||||
}
|
||||
Class clazz;
|
||||
try {
|
||||
clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
clazz = FactoryFinder.class.getClassLoader().loadClass(className);
|
||||
}
|
||||
|
||||
return clazz;
|
||||
}
|
||||
|
||||
private Properties doFindFactoryProperies(String key) throws IOException {
|
||||
String uri = path + key;
|
||||
|
||||
// lets try the thread context class loader first
|
||||
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri);
|
||||
if (in == null) {
|
||||
in = FactoryFinder.class.getClassLoader().getResourceAsStream(uri);
|
||||
if (in == null) {
|
||||
throw new IOException("Could not find factory class for resource: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
// lets load the file
|
||||
BufferedInputStream reader = null;
|
||||
try {
|
||||
reader = new BufferedInputStream(in);
|
||||
Properties properties = new Properties();
|
||||
properties.load(reader);
|
||||
return properties;
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* A AsyncChannelFilter can be used as a filter between a {@see org.activeio.AsyncChannel}
|
||||
* and it's {@see org.activeio.ChannelConsumer}. Most {@see org.activeio.AsyncChannel}
|
||||
* that are not directly accessing the network will extends the AsyncChannelFilter since they act as a
|
||||
* filter between the client and the network. O
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class FilterAsyncChannel implements AsyncChannel, AsyncChannelListener {
|
||||
|
||||
final protected AsyncChannel next;
|
||||
protected AsyncChannelListener channelListener;
|
||||
|
||||
public FilterAsyncChannel(AsyncChannel next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public void setAsyncChannelListener(AsyncChannelListener channelListener) {
|
||||
this.channelListener = channelListener;
|
||||
if (channelListener == null)
|
||||
next.setAsyncChannelListener(null);
|
||||
else
|
||||
next.setAsyncChannelListener(this);
|
||||
}
|
||||
|
||||
public void write(Packet packet) throws IOException {
|
||||
next.write(packet);
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
next.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Disposable#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
next.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#start()
|
||||
* @throws IOException if the next channel has not been set.
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
if( next == null )
|
||||
throw new IOException("The next channel has not been set.");
|
||||
if( channelListener ==null )
|
||||
throw new IOException("The UpPacketListener has not been set.");
|
||||
next.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#stop(long)
|
||||
*/
|
||||
public void stop(long timeout) throws IOException {
|
||||
next.stop(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.AsyncChannelListener#onPacket(org.activeio.Packet)
|
||||
*/
|
||||
public void onPacket(Packet packet) {
|
||||
channelListener.onPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.AsyncChannelListener#onPacketError(org.activeio.ChannelException)
|
||||
*/
|
||||
public void onPacketError(IOException error) {
|
||||
channelListener.onPacketError(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the next.
|
||||
*/
|
||||
public AsyncChannel getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the packetListener.
|
||||
*/
|
||||
public AsyncChannelListener getAsyncChannelListener() {
|
||||
return channelListener;
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
if( target.isAssignableFrom(getClass()) ) {
|
||||
return this;
|
||||
}
|
||||
return next.getAdapter(target);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return next.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
/**
|
||||
* A AsyncChannelFilter can be used as a filter between a {@see org.activeio.AsyncChannel}
|
||||
* and it's {@see org.activeio.ChannelConsumer}. Most {@see org.activeio.AsyncChannel}
|
||||
* that are not directly accessing the network will extends the AsyncChannelFilter since they act as a
|
||||
* filter between the client and the network. O
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class FilterAsyncChannelServer implements AsyncChannelServer, AcceptListener {
|
||||
|
||||
final protected AsyncChannelServer next;
|
||||
protected AcceptListener acceptListener;
|
||||
|
||||
public FilterAsyncChannelServer(AsyncChannelServer next) {
|
||||
this.next = next;
|
||||
if( next == null )
|
||||
throw new IllegalArgumentException("The next AsyncChannelServer cannot be null.");
|
||||
}
|
||||
|
||||
public void setAcceptListener(AcceptListener acceptListener) {
|
||||
this.acceptListener = acceptListener;
|
||||
if (acceptListener == null)
|
||||
next.setAcceptListener(null);
|
||||
else
|
||||
next.setAcceptListener(this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Disposable#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
next.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#start()
|
||||
* @throws IOException if the next channel has not been set.
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
if( acceptListener ==null )
|
||||
throw new IOException("The AcceptListener has not been set.");
|
||||
next.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#stop(long)
|
||||
*/
|
||||
public void stop(long timeout) throws IOException {
|
||||
next.stop(timeout);
|
||||
}
|
||||
|
||||
public void onAccept(Channel channel) {
|
||||
acceptListener.onAccept(channel);
|
||||
}
|
||||
|
||||
public void onAcceptError(IOException error) {
|
||||
acceptListener.onAcceptError(error);
|
||||
}
|
||||
|
||||
public URI getBindURI() {
|
||||
return next.getBindURI();
|
||||
}
|
||||
|
||||
public URI getConnectURI() {
|
||||
return next.getConnectURI();
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
if( target.isAssignableFrom(getClass()) ) {
|
||||
return this;
|
||||
}
|
||||
return next.getAdapter(target);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return next.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* A SynchChannelFilter can be used as a filter another {@see org.activeio.SynchChannel}
|
||||
* Most {@see org.activeio.SynchChannel} that are not directly accessing the network will
|
||||
* extends the SynchChannelFilter since they act as a filter between the client and the network.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class FilterSyncChannel implements SyncChannel {
|
||||
|
||||
private final SyncChannel next;
|
||||
|
||||
public FilterSyncChannel(SyncChannel next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Channel#write(org.activeio.Packet)
|
||||
*/
|
||||
public void write(Packet packet) throws IOException {
|
||||
next.write(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Channel#flush()
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
next.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Disposable#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
next.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#start()
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
next.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#stop(long)
|
||||
*/
|
||||
public void stop(long timeout) throws IOException {
|
||||
next.stop(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the next.
|
||||
*/
|
||||
public SyncChannel getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.SyncChannel#read(long)
|
||||
*/
|
||||
public Packet read(long timeout) throws IOException {
|
||||
return next.read(timeout);
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
if( target.isAssignableFrom(getClass()) ) {
|
||||
return this;
|
||||
}
|
||||
return next.getAdapter(target);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return next.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
/**
|
||||
* A SynchChannelFilter can be used as a filter another {@see org.activeio.SynchChannel}
|
||||
* Most {@see org.activeio.SynchChannel} that are not directly accessing the network will
|
||||
* extends the SynchChannelFilter since they act as a filter between the client and the network.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class FilterSyncChannelServer implements SyncChannelServer {
|
||||
|
||||
private final SyncChannelServer next;
|
||||
|
||||
public FilterSyncChannelServer(SyncChannelServer next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Disposable#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
next.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#start()
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
next.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#stop(long)
|
||||
*/
|
||||
public void stop(long timeout) throws IOException {
|
||||
next.stop(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the next.
|
||||
*/
|
||||
public SyncChannelServer getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.SyncChannelServer#accept(long)
|
||||
*/
|
||||
public Channel accept(long timeout) throws IOException {
|
||||
return next.accept(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.ChannelServer#getBindURI()
|
||||
*/
|
||||
public URI getBindURI() {
|
||||
return next.getBindURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.ChannelServer#getConnectURI()
|
||||
*/
|
||||
public URI getConnectURI() {
|
||||
return next.getConnectURI();
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
if( target.isAssignableFrom(getClass()) ) {
|
||||
return this;
|
||||
}
|
||||
return next.getAdapter(target);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return next.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* InputAsyncChannel objects asynchronously push 'up' {@see org.activeio.Packet} objects
|
||||
* to a registered {@see org.activeio.AsyncChannelListener}.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface InputAsyncChannel extends Channel {
|
||||
|
||||
/**
|
||||
* Registers the {@see ChannelConsumer} that the protcol will use to deliver packets
|
||||
* coming 'up' the channel.
|
||||
*
|
||||
* @param packetListener
|
||||
*/
|
||||
void setAsyncChannelListener(AsyncChannelListener channelListener);
|
||||
|
||||
/**
|
||||
* @return the registered Packet consumer
|
||||
*/
|
||||
AsyncChannelListener getAsyncChannelListener();
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface InputStreamChannel extends Channel {
|
||||
|
||||
public int available() throws IOException;
|
||||
public void mark(int arg0);
|
||||
public boolean markSupported();
|
||||
public int read(byte[] arg0, int arg1, int arg2) throws IOException;
|
||||
public int read(byte[] arg0) throws IOException;
|
||||
public void reset() throws IOException;
|
||||
public long skip(long arg0) throws IOException;
|
||||
public int read() throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* SynchChannel objects allow threaded to synchronously block on the <code>read</code>
|
||||
* method to get {@see org.activeio.Packet} objects when they arrive from the peer.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface InputSyncChannel extends Channel {
|
||||
|
||||
/**
|
||||
* Used to synchronously receive a packet of information going 'up' the channel.
|
||||
* This method blocks until a packet is received or the operation experiences timeout.
|
||||
*
|
||||
* @param timeout
|
||||
* @return the packet received or null if the timeout occurred.
|
||||
* @throws IOException
|
||||
*/
|
||||
Packet read(long timeout) throws IOException;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface OutputChannel extends Channel {
|
||||
|
||||
/**
|
||||
* Sends a packet down the channel towards the media.
|
||||
*
|
||||
* @param packet
|
||||
* @throws IOException
|
||||
*/
|
||||
void write(Packet packet) throws IOException;
|
||||
|
||||
/**
|
||||
* Some channels may buffer data which may be sent down if flush() is called.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void flush() throws IOException;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface OutputStreamChannel extends Channel {
|
||||
|
||||
public void write(byte[] data, int pos, int length) throws IOException;
|
||||
public void write(byte[] data) throws IOException;
|
||||
public void write(int data) throws IOException;
|
||||
|
||||
/**
|
||||
* Some channels may buffer data which may be sent down if flush() is called.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void flush() throws IOException;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chrino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Provides a ByteBuffer like interface to work with IO channel packets of data.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Packet extends Disposable, Adaptable {
|
||||
|
||||
public int position();
|
||||
public void position(int position);
|
||||
public int limit();
|
||||
public void limit(int limit);
|
||||
public void flip();
|
||||
public int remaining();
|
||||
public void rewind();
|
||||
public boolean hasRemaining();
|
||||
public void clear();
|
||||
public Packet slice();
|
||||
public Packet duplicate();
|
||||
public Object duplicate(ClassLoader cl) throws IOException;
|
||||
public int capacity();
|
||||
|
||||
public ByteSequence asByteSequence();
|
||||
public byte[] sliceAsBytes();
|
||||
|
||||
|
||||
/**
|
||||
* Writes the remaing bytes in the packet to the output stream.
|
||||
*
|
||||
* @param out
|
||||
* @return
|
||||
*/
|
||||
void writeTo(OutputStream out) throws IOException;
|
||||
void writeTo(DataOutput out) throws IOException;
|
||||
|
||||
// To read data out of the packet.
|
||||
public int read();
|
||||
public int read(byte data[], int offset, int length);
|
||||
|
||||
// To write data into the packet.
|
||||
public boolean write( int data );
|
||||
public int write( byte data[], int offset, int length );
|
||||
public int read(Packet dest);
|
||||
|
||||
}
|
|
@ -0,0 +1,382 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Used to write and read primitives to and from a Packet.
|
||||
*/
|
||||
final public class PacketData {
|
||||
|
||||
final private Packet packet;
|
||||
private final boolean bigEndian;
|
||||
|
||||
public PacketData(Packet packet) {
|
||||
this(packet, true);
|
||||
}
|
||||
|
||||
public PacketData(Packet packet, boolean bigEndian) {
|
||||
this.packet = packet;
|
||||
this.bigEndian = bigEndian;
|
||||
}
|
||||
|
||||
private static void spaceNeeded(Packet packet, int space) throws IOException {
|
||||
if (packet.remaining() < space)
|
||||
throw new EOFException("Not enough space left in the packet.");
|
||||
}
|
||||
|
||||
public void readFully(byte[] b) throws IOException {
|
||||
readFully(packet, b, 0, b.length);
|
||||
}
|
||||
|
||||
public static void readFully(Packet packet, byte[] b) throws IOException {
|
||||
readFully(packet, b, 0, b.length);
|
||||
}
|
||||
|
||||
public void readFully(byte[] b, int off, int len) throws IOException {
|
||||
readFully(packet, b, off, len);
|
||||
}
|
||||
public static void readFully(Packet packet, byte[] b, int off, int len) throws IOException {
|
||||
spaceNeeded(packet, len);
|
||||
packet.read(b, off, len);
|
||||
}
|
||||
|
||||
public int skipBytes(int n) throws IOException {
|
||||
return skipBytes(packet, n);
|
||||
}
|
||||
public static int skipBytes(Packet packet, int n) throws IOException {
|
||||
int rc = Math.min(n, packet.remaining());
|
||||
packet.position(packet.position() + rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
public boolean readBoolean() throws IOException {
|
||||
return readBoolean(packet);
|
||||
}
|
||||
public static boolean readBoolean(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 1);
|
||||
return packet.read() != 0;
|
||||
}
|
||||
|
||||
public byte readByte() throws IOException {
|
||||
return readByte(packet);
|
||||
}
|
||||
public static byte readByte(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 1);
|
||||
return (byte) packet.read();
|
||||
}
|
||||
|
||||
public int readUnsignedByte() throws IOException {
|
||||
return readUnsignedByte(packet);
|
||||
}
|
||||
public static int readUnsignedByte(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 1);
|
||||
return packet.read();
|
||||
}
|
||||
|
||||
public short readShort() throws IOException {
|
||||
if( bigEndian ) {
|
||||
return readShortBig(packet);
|
||||
} else {
|
||||
return readShortLittle(packet);
|
||||
}
|
||||
}
|
||||
public static short readShortBig(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
return (short) ((packet.read() << 8) + (packet.read() << 0));
|
||||
}
|
||||
public static short readShortLittle(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
return (short) ((packet.read() << 0) + (packet.read() << 8) );
|
||||
}
|
||||
|
||||
public int readUnsignedShort() throws IOException {
|
||||
if( bigEndian ) {
|
||||
return readUnsignedShortBig(packet);
|
||||
} else {
|
||||
return readUnsignedShortLittle(packet);
|
||||
}
|
||||
}
|
||||
public static int readUnsignedShortBig(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
return ((packet.read() << 8) + (packet.read() << 0));
|
||||
}
|
||||
public static int readUnsignedShortLittle(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
return ((packet.read() << 0) + (packet.read() << 8) );
|
||||
}
|
||||
|
||||
public char readChar() throws IOException {
|
||||
if( bigEndian ) {
|
||||
return readCharBig(packet);
|
||||
} else {
|
||||
return readCharLittle(packet);
|
||||
}
|
||||
}
|
||||
public static char readCharBig(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
return (char) ((packet.read() << 8) + (packet.read() << 0));
|
||||
}
|
||||
public static char readCharLittle(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
return (char) ((packet.read() << 0) + (packet.read() << 8) );
|
||||
}
|
||||
|
||||
public int readInt() throws IOException {
|
||||
if( bigEndian ) {
|
||||
return readIntBig(packet);
|
||||
} else {
|
||||
return readIntLittle(packet);
|
||||
}
|
||||
}
|
||||
public static int readIntBig(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 4);
|
||||
return ((packet.read() << 24) +
|
||||
(packet.read() << 16) +
|
||||
(packet.read() << 8) +
|
||||
(packet.read() << 0));
|
||||
}
|
||||
public static int readIntLittle(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 4);
|
||||
return ((packet.read() << 0) +
|
||||
(packet.read() << 8) +
|
||||
(packet.read() << 16) +
|
||||
(packet.read() << 24));
|
||||
}
|
||||
|
||||
public long readLong() throws IOException {
|
||||
if( bigEndian ) {
|
||||
return readLongBig(packet);
|
||||
} else {
|
||||
return readLongLittle(packet);
|
||||
}
|
||||
}
|
||||
public static long readLongBig(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 8);
|
||||
return (((long) packet.read() << 56) +
|
||||
((long) packet.read() << 48) +
|
||||
((long) packet.read() << 40) +
|
||||
((long) packet.read() << 32) +
|
||||
((long) packet.read() << 24) +
|
||||
((packet.read()) << 16) +
|
||||
((packet.read()) << 8) +
|
||||
((packet.read()) << 0));
|
||||
}
|
||||
public static long readLongLittle(Packet packet) throws IOException {
|
||||
spaceNeeded(packet, 8);
|
||||
return ((packet.read() << 0) +
|
||||
(packet.read() << 8) +
|
||||
(packet.read() << 16) +
|
||||
((long) packet.read() << 24) +
|
||||
((long) packet.read() << 32) +
|
||||
((long) packet.read() << 40) +
|
||||
((long) packet.read() << 48) +
|
||||
((long) packet.read() << 56));
|
||||
}
|
||||
|
||||
public double readDouble() throws IOException {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
public static double readDoubleBig(Packet packet) throws IOException {
|
||||
return Double.longBitsToDouble(readLongBig(packet));
|
||||
}
|
||||
public static double readDoubleLittle(Packet packet) throws IOException {
|
||||
return Double.longBitsToDouble(readLongLittle(packet));
|
||||
}
|
||||
|
||||
public float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat(readInt());
|
||||
}
|
||||
public static float readFloatBig(Packet packet) throws IOException {
|
||||
return Float.intBitsToFloat(readIntBig(packet));
|
||||
}
|
||||
public static float readFloatLittle(Packet packet) throws IOException {
|
||||
return Float.intBitsToFloat(readIntLittle(packet));
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
write(packet, b);
|
||||
}
|
||||
public static void write(Packet packet, int b) throws IOException {
|
||||
spaceNeeded(packet, 1);
|
||||
packet.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b) throws IOException {
|
||||
write(packet, b, 0, b.length);
|
||||
}
|
||||
public static void write(Packet packet, byte[] b) throws IOException {
|
||||
write(packet, b, 0, b.length);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
write(packet, b, off, len);
|
||||
}
|
||||
public static void write(Packet packet, byte[] b, int off, int len) throws IOException {
|
||||
spaceNeeded(packet, len);
|
||||
packet.write(b, off, len);
|
||||
}
|
||||
|
||||
public void writeBoolean(boolean v) throws IOException {
|
||||
writeBoolean(packet, v);
|
||||
}
|
||||
public static void writeBoolean(Packet packet, boolean v) throws IOException {
|
||||
spaceNeeded(packet, 1);
|
||||
packet.write(v ? 1 : 0);
|
||||
}
|
||||
|
||||
public void writeByte(int v) throws IOException {
|
||||
writeByte(packet, v);
|
||||
}
|
||||
public static void writeByte(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 1);
|
||||
packet.write(v);
|
||||
}
|
||||
|
||||
public void writeShort(int v) throws IOException {
|
||||
if (bigEndian) {
|
||||
writeShortBig(packet,v);
|
||||
} else {
|
||||
writeShortLittle(packet,v);
|
||||
}
|
||||
}
|
||||
public static void writeShortBig(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
packet.write((v >>> 8) & 0xFF);
|
||||
packet.write((v >>> 0) & 0xFF);
|
||||
}
|
||||
public static void writeShortLittle(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
packet.write((v >>> 0) & 0xFF);
|
||||
packet.write((v >>> 8) & 0xFF);
|
||||
}
|
||||
|
||||
public void writeChar(int v) throws IOException {
|
||||
if (bigEndian) {
|
||||
writeCharBig(packet, v);
|
||||
} else {
|
||||
writeCharLittle(packet, v);
|
||||
}
|
||||
}
|
||||
public static void writeCharBig(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
packet.write((v >>> 8) & 0xFF);
|
||||
packet.write((v >>> 0) & 0xFF);
|
||||
}
|
||||
public static void writeCharLittle(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 2);
|
||||
packet.write((v >>> 0) & 0xFF);
|
||||
packet.write((v >>> 8) & 0xFF);
|
||||
}
|
||||
|
||||
public void writeInt(int v) throws IOException {
|
||||
if (bigEndian) {
|
||||
writeIntBig(packet, v);
|
||||
} else {
|
||||
writeIntLittle(packet, v);
|
||||
}
|
||||
}
|
||||
public static void writeIntBig(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 4);
|
||||
packet.write((v >>> 24) & 0xFF);
|
||||
packet.write((v >>> 16) & 0xFF);
|
||||
packet.write((v >>> 8) & 0xFF);
|
||||
packet.write((v >>> 0) & 0xFF);
|
||||
}
|
||||
public static void writeIntLittle(Packet packet, int v) throws IOException {
|
||||
spaceNeeded(packet, 4);
|
||||
packet.write((v >>> 0) & 0xFF);
|
||||
packet.write((v >>> 8) & 0xFF);
|
||||
packet.write((v >>> 16) & 0xFF);
|
||||
packet.write((v >>> 24) & 0xFF);
|
||||
}
|
||||
|
||||
public void writeLong(long v) throws IOException {
|
||||
if (bigEndian) {
|
||||
writeLongBig(packet, v);
|
||||
} else {
|
||||
writeLongLittle(packet, v);
|
||||
}
|
||||
}
|
||||
public static void writeLongBig(Packet packet, long v) throws IOException {
|
||||
spaceNeeded(packet, 8);
|
||||
packet.write((int) (v >>> 56) & 0xFF);
|
||||
packet.write((int) (v >>> 48) & 0xFF);
|
||||
packet.write((int) (v >>> 40) & 0xFF);
|
||||
packet.write((int) (v >>> 32) & 0xFF);
|
||||
packet.write((int) (v >>> 24) & 0xFF);
|
||||
packet.write((int) (v >>> 16) & 0xFF);
|
||||
packet.write((int) (v >>> 8) & 0xFF);
|
||||
packet.write((int) (v >>> 0) & 0xFF);
|
||||
}
|
||||
public static void writeLongLittle(Packet packet, long v) throws IOException {
|
||||
spaceNeeded(packet, 8);
|
||||
packet.write((int) (v >>> 0) & 0xFF);
|
||||
packet.write((int) (v >>> 8) & 0xFF);
|
||||
packet.write((int) (v >>> 16) & 0xFF);
|
||||
packet.write((int) (v >>> 24) & 0xFF);
|
||||
packet.write((int) (v >>> 32) & 0xFF);
|
||||
packet.write((int) (v >>> 40) & 0xFF);
|
||||
packet.write((int) (v >>> 48) & 0xFF);
|
||||
packet.write((int) (v >>> 56) & 0xFF);
|
||||
}
|
||||
|
||||
public void writeDouble(double v) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(v));
|
||||
}
|
||||
public static void writeDoubleBig(Packet packet, double v) throws IOException {
|
||||
writeLongBig(packet, Double.doubleToLongBits(v));
|
||||
}
|
||||
public static void writeDoubleLittle(Packet packet, double v) throws IOException {
|
||||
writeLongLittle(packet, Double.doubleToLongBits(v));
|
||||
}
|
||||
|
||||
public void writeFloat(float v) throws IOException {
|
||||
writeInt(Float.floatToIntBits(v));
|
||||
}
|
||||
public static void writeFloatBig(Packet packet, float v) throws IOException {
|
||||
writeIntBig(packet, Float.floatToIntBits(v));
|
||||
}
|
||||
public static void writeFloatLittle(Packet packet, float v) throws IOException {
|
||||
writeIntLittle(packet, Float.floatToIntBits(v));
|
||||
}
|
||||
|
||||
public void writeRawDouble(double v) throws IOException {
|
||||
writeLong(Double.doubleToRawLongBits(v));
|
||||
}
|
||||
public static void writeRawDoubleBig(Packet packet, double v) throws IOException {
|
||||
writeLongBig(packet, Double.doubleToRawLongBits(v));
|
||||
}
|
||||
public static void writeRawDoubleLittle(Packet packet, double v) throws IOException {
|
||||
writeLongLittle(packet, Double.doubleToRawLongBits(v));
|
||||
}
|
||||
|
||||
public void writeRawFloat(float v) throws IOException {
|
||||
writeInt(Float.floatToRawIntBits(v));
|
||||
}
|
||||
public static void writeRawFloatBig(Packet packet, float v) throws IOException {
|
||||
writeIntBig(packet, Float.floatToRawIntBits(v));
|
||||
}
|
||||
public static void writeRawFloatLittle(Packet packet, float v) throws IOException {
|
||||
writeIntLittle(packet, Float.floatToRawIntBits(v));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* RequestChannel are used to model the request/reponse exchange that is used
|
||||
* by higher level protcols such as HTTP and RMI.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface RequestChannel extends Channel {
|
||||
|
||||
/**
|
||||
* Used to send a packet of information going 'down' the channel and wait for
|
||||
* it's reponse 'up' packet.
|
||||
*
|
||||
* This method blocks until the response packet is received or the operation
|
||||
* experiences a timeout.
|
||||
*
|
||||
* @param request
|
||||
* @param timeout
|
||||
* @return the respnse packet or null if the timeout occured.
|
||||
* @throws IOException
|
||||
*/
|
||||
Packet request(Packet request, long timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Registers the {@see RequestListener} that the protcol will use to deliver request packets
|
||||
* comming 'up' the channel.
|
||||
*
|
||||
* @param packetListener
|
||||
* @throws IOException
|
||||
*/
|
||||
void setRequestListener(RequestListener requestListener) throws IOException;
|
||||
|
||||
/**
|
||||
* @return the registered RequestListener
|
||||
*/
|
||||
RequestListener getRequestListener();
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* An RequestListener object is used to receive remote requests from a a {@see org.activeio.RequestChannel}
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface RequestListener {
|
||||
|
||||
/**
|
||||
* A {@see RequestChannel} will call this method when a new request arrives.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
Packet onRequest(Packet request);
|
||||
|
||||
/**
|
||||
* A {@see RequestChannel} will call this method when a async failure occurs when receiving a request.
|
||||
*
|
||||
* @param error the exception that describes the failure.
|
||||
*/
|
||||
void onRquestError(IOException error);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The Service interface is used control the running state of a channel.
|
||||
*
|
||||
* Some channels may use background threads to provide SEDA style processing. By
|
||||
* implenting the Service interface, a protcol can allow a container to
|
||||
* control those threads.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Service {
|
||||
|
||||
static final public long NO_WAIT_TIMEOUT=0;
|
||||
static final public long WAIT_FOREVER_TIMEOUT=-1;
|
||||
|
||||
/**
|
||||
* Starts the channel. Once started, the channel is in the running state.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void start() throws IOException;
|
||||
|
||||
/**
|
||||
* Stops the channel. Once stopped, the channel is in the stopped state.
|
||||
*
|
||||
* @param timeout The amount of time the channel is allowed to take to gracefully stop. If the timeout
|
||||
* is exceeded, the channel should do a forcefull stop.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void stop(long timeout) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface StreamChannel extends OutputStreamChannel, InputStreamChannel {
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* StreamChannelFactory objects can create {@see org.activeio.StreamChannel}
|
||||
* and {@see org.activeio.StreamChannelServer} objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface StreamChannelFactory {
|
||||
|
||||
/**
|
||||
* Opens a connection to server.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public StreamChannel openStreamChannel(URI location) throws IOException;
|
||||
|
||||
/**
|
||||
* Binds a server at the URI location.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public StreamChannelServer bindStreamChannel(URI location) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A StreamChannelServer object provides an <code>accept</code> method to synchronously
|
||||
* accept and create {@see org.activeio.channel.Channel} objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface StreamChannelServer extends ChannelServer {
|
||||
|
||||
static final public long NO_WAIT_TIMEOUT=0;
|
||||
static final public long WAIT_FOREVER_TIMEOUT=-1;
|
||||
|
||||
public Channel accept(long timeout) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
/**
|
||||
* SyncChannel objets allow threadd to synchronously block on the <code>receiveUpPacket</code>
|
||||
* method to get 'up' {@see org.activeio.Packet} objects when they arrive.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface SyncChannel extends OutputChannel, InputSyncChannel {
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* SynchChannelFactory objects can create {@see org.activeio.SynchChannel}
|
||||
* and {@see org.activeio.SynchChannelServer} objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface SyncChannelFactory {
|
||||
|
||||
/**
|
||||
* Opens a connection to server.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public SyncChannel openSyncChannel(URI location) throws IOException;
|
||||
|
||||
/**
|
||||
* Binds a server at the URI location.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public SyncChannelServer bindSyncChannel(URI location) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A SynchChannelServer object provides an <code>accept</code> method to synchronously
|
||||
* accept and create {@see org.activeio.Channel} objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface SyncChannelServer extends ChannelServer {
|
||||
|
||||
static final public long NO_WAIT_TIMEOUT=0;
|
||||
static final public long WAIT_FOREVER_TIMEOUT=-1;
|
||||
|
||||
public Channel accept(long timeout) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.activeio.Packet;
|
||||
import org.activeio.RequestChannel;
|
||||
import org.activeio.RequestListener;
|
||||
import org.activeio.SyncChannel;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@see org.activeio.RequestChannel} out of a {@see org.activeio.SyncChannel}.
|
||||
* Does not support handing requests. It can only be used to send requests.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
final public class AsyncChannelToClientRequestChannel implements RequestChannel {
|
||||
|
||||
private final SyncChannel next;
|
||||
|
||||
public AsyncChannelToClientRequestChannel(SyncChannel next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public Packet request(Packet request, long timeout) throws IOException {
|
||||
next.write(request);
|
||||
next.flush();
|
||||
return next.read(timeout);
|
||||
}
|
||||
|
||||
public void setRequestListener(RequestListener requestListener) throws IOException {
|
||||
throw new IOException("Operation not supported.");
|
||||
}
|
||||
|
||||
public RequestListener getRequestListener() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
return next.getAdapter(target);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
next.dispose();
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
next.start();
|
||||
}
|
||||
|
||||
public void stop(long timeout) throws IOException {
|
||||
next.stop(timeout);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import org.activeio.AsyncChannel;
|
||||
import org.activeio.ChannelFactory;
|
||||
import org.activeio.FilterAsyncChannel;
|
||||
import org.activeio.Packet;
|
||||
import org.activeio.PacketData;
|
||||
import org.activeio.RequestChannel;
|
||||
import org.activeio.RequestListener;
|
||||
import org.activeio.packet.AppendedPacket;
|
||||
import org.activeio.packet.ByteArrayPacket;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.Executor;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@see org.activeio.RequestChannel} out of a {@see org.activeio.AsyncChannel}. This
|
||||
* {@see org.activeio.RequestChannel} is thread safe and mutiplexes concurrent requests and responses over
|
||||
* the underlying {@see org.activeio.AsyncChannel}.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
final public class AsyncChannelToConcurrentRequestChannel extends FilterAsyncChannel implements RequestChannel {
|
||||
|
||||
private static final byte PASSTHROUGH = 0x00;
|
||||
private static final byte REQUEST = 0x01;
|
||||
private static final byte RESPONSE = 0x02;
|
||||
private static final ByteArrayPacket PASSTHROUGH_PACKET = new ByteArrayPacket(new byte[]{PASSTHROUGH});
|
||||
|
||||
private final ConcurrentHashMap requestMap = new ConcurrentHashMap();
|
||||
private final Executor requestExecutor;
|
||||
private short nextRequestId = 0;
|
||||
private final Object writeMutex = new Object();
|
||||
|
||||
private RequestListener requestListener;
|
||||
|
||||
public AsyncChannelToConcurrentRequestChannel(AsyncChannel next) {
|
||||
this(next, ChannelFactory.DEFAULT_EXECUTOR);
|
||||
}
|
||||
|
||||
public AsyncChannelToConcurrentRequestChannel(AsyncChannel next, Executor requestExecutor) {
|
||||
super(next);
|
||||
this.requestExecutor=requestExecutor;
|
||||
}
|
||||
|
||||
synchronized short getNextRequestId() {
|
||||
return nextRequestId++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.FilterAsyncChannel#write(org.activeio.Packet)
|
||||
*/
|
||||
public void write(Packet packet) throws IOException {
|
||||
Packet passThrough = AppendedPacket.join(PASSTHROUGH_PACKET.duplicate(), packet);
|
||||
synchronized(writeMutex) {
|
||||
super.write(passThrough);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.FilterAsyncChannel#onPacket(org.activeio.Packet)
|
||||
*/
|
||||
public void onPacket(final Packet packet) {
|
||||
switch( packet.read() ) {
|
||||
case PASSTHROUGH:
|
||||
super.onPacket(packet);
|
||||
break;
|
||||
case REQUEST:
|
||||
requestExecutor.execute(new Runnable(){
|
||||
public void run() {
|
||||
serviceRequest(packet);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case RESPONSE:
|
||||
serviceReponse(packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void serviceRequest(Packet packet) {
|
||||
try {
|
||||
if( requestListener ==null )
|
||||
throw new IOException("The RequestListener has not been set.");
|
||||
|
||||
PacketData data = new PacketData(packet);
|
||||
short requestId = data.readShort();
|
||||
Packet reponse = requestListener.onRequest(packet);
|
||||
|
||||
// Send the response...
|
||||
Packet header = createHeaderPacket(RESPONSE, requestId);
|
||||
Packet rc = AppendedPacket.join(header, packet);
|
||||
synchronized(writeMutex) {
|
||||
super.write(rc);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
super.onPacketError(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void serviceReponse(Packet packet) {
|
||||
|
||||
try {
|
||||
|
||||
PacketData data = new PacketData(packet);
|
||||
short requestId = data.readShort();
|
||||
|
||||
ArrayBlockingQueue responseSlot = (ArrayBlockingQueue) requestMap.get(new Short(requestId));
|
||||
responseSlot.put(packet);
|
||||
|
||||
} catch (IOException e) {
|
||||
super.onPacketError(e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Packet request(Packet request, long timeout) throws IOException {
|
||||
|
||||
Short requestId = new Short(getNextRequestId());
|
||||
ArrayBlockingQueue responseSlot = new ArrayBlockingQueue(1);
|
||||
requestMap.put(requestId, responseSlot);
|
||||
|
||||
Packet header = createHeaderPacket(REQUEST, requestId.shortValue());
|
||||
Packet packet = AppendedPacket.join(header, request);
|
||||
|
||||
synchronized(writeMutex) {
|
||||
super.write(packet);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if( timeout == WAIT_FOREVER_TIMEOUT ) {
|
||||
return (Packet) responseSlot.take();
|
||||
} else if (timeout == NO_WAIT_TIMEOUT ) {
|
||||
return (Packet) responseSlot.poll(1, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
return (Packet) responseSlot.poll(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedIOException(e.getMessage());
|
||||
} finally {
|
||||
requestMap.remove(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
private Packet createHeaderPacket(byte type, short requestId) throws IOException {
|
||||
ByteArrayPacket header = new ByteArrayPacket(new byte[]{3});
|
||||
PacketData data = new PacketData(header);
|
||||
data.writeByte(type);
|
||||
data.writeShort(requestId);
|
||||
header.flip();
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setRequestListener(RequestListener requestListener) throws IOException {
|
||||
this.requestListener = requestListener;
|
||||
}
|
||||
|
||||
public RequestListener getRequestListener() {
|
||||
return requestListener;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.activeio.AsyncChannel;
|
||||
import org.activeio.packet.ByteArrayPacket;
|
||||
import org.activeio.packet.BytePacket;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class AsyncChannelToOutputStream extends OutputStream {
|
||||
|
||||
private final AsyncChannel channel;
|
||||
private boolean closed;
|
||||
|
||||
/**
|
||||
* @param channel
|
||||
*/
|
||||
public AsyncChannelToOutputStream(AsyncChannel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.OutputStream#write(int)
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
channel.write(new BytePacket((byte) b));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.OutputStream#write(byte[], int, int)
|
||||
*/
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
channel.write(new ByteArrayPacket(b, off, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.OutputStream#flush()
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
channel.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.InputStream#close()
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
closed=true;
|
||||
super.close();
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.activeio.AsyncChannel;
|
||||
import org.activeio.AsyncChannelListener;
|
||||
import org.activeio.Packet;
|
||||
import org.activeio.RequestChannel;
|
||||
import org.activeio.RequestListener;
|
||||
import org.activeio.packet.EOSPacket;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@see org.activeio.RequestChannel} out of a {@see org.activeio.AsyncChannel}.
|
||||
* Does not support sending requests. It can only be used to handle requests.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class AsyncChannelToServerRequestChannel implements RequestChannel, AsyncChannelListener {
|
||||
|
||||
private final AsyncChannel next;
|
||||
private RequestListener requestListener;
|
||||
|
||||
public AsyncChannelToServerRequestChannel(AsyncChannel next) throws IOException {
|
||||
this.next = next;
|
||||
next.setAsyncChannelListener(this);
|
||||
}
|
||||
|
||||
public Packet request(Packet request, long timeout) throws IOException {
|
||||
throw new IOException("Operation not supported.");
|
||||
}
|
||||
|
||||
public void setRequestListener(RequestListener requestListener) throws IOException {
|
||||
this.requestListener = requestListener;
|
||||
}
|
||||
|
||||
public RequestListener getRequestListener() {
|
||||
return requestListener;
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
return next.getAdapter(target);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
next.dispose();
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
next.start();
|
||||
}
|
||||
|
||||
public void stop(long timeout) throws IOException {
|
||||
next.stop(timeout);
|
||||
}
|
||||
|
||||
public void onPacket(Packet packet) {
|
||||
if( packet == EOSPacket.EOS_PACKET ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Packet response = requestListener.onRequest(packet);
|
||||
next.write(response);
|
||||
next.flush();
|
||||
} catch (IOException e) {
|
||||
requestListener.onRquestError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPacketError(IOException error) {
|
||||
requestListener.onRquestError(error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import org.activeio.AsyncChannel;
|
||||
import org.activeio.AsyncChannelListener;
|
||||
import org.activeio.Packet;
|
||||
import org.activeio.SyncChannel;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Adapts a {@see org.activeio.AsyncChannel} so that it provides an
|
||||
* {@see org.activeio.SynchChannel} interface.
|
||||
*
|
||||
* This object buffers asynchronous messages from the {@see org.activeio.AsyncChannel}
|
||||
* and buffers them in a {@see edu.emory.mathcs.backport.java.util.concurrent.Channel} util the client receives them.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
final public class AsyncToSyncChannel implements SyncChannel, AsyncChannelListener {
|
||||
|
||||
private final AsyncChannel asyncChannel;
|
||||
private final BlockingQueue buffer;
|
||||
|
||||
static public SyncChannel adapt(org.activeio.Channel channel) {
|
||||
return adapt(channel, new LinkedBlockingQueue());
|
||||
}
|
||||
|
||||
static public SyncChannel adapt(org.activeio.Channel channel, BlockingQueue upPacketChannel) {
|
||||
|
||||
// It might not need adapting
|
||||
if( channel instanceof SyncChannel ) {
|
||||
return (SyncChannel) channel;
|
||||
}
|
||||
|
||||
// Can we just just undo the adaptor
|
||||
if( channel.getClass() == SyncToAsyncChannel.class ) {
|
||||
return ((SyncToAsyncChannel)channel).getSynchChannel();
|
||||
}
|
||||
|
||||
return new AsyncToSyncChannel((AsyncChannel)channel, upPacketChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@see #adapt(AsyncChannel)}
|
||||
*/
|
||||
public AsyncToSyncChannel(AsyncChannel asyncChannel) {
|
||||
this(asyncChannel, new LinkedBlockingQueue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@see #adapt(AsyncChannel, Channel)}
|
||||
*/
|
||||
public AsyncToSyncChannel(AsyncChannel asyncChannel, BlockingQueue upPacketChannel){
|
||||
this.asyncChannel = asyncChannel;
|
||||
this.asyncChannel.setAsyncChannelListener(this);
|
||||
this.buffer=upPacketChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Channel#write(org.activeio.Packet)
|
||||
*/
|
||||
public void write(org.activeio.Packet packet) throws IOException {
|
||||
asyncChannel.write(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Channel#flush()
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
asyncChannel.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.SyncChannel#read(long)
|
||||
*/
|
||||
public Packet read(long timeout) throws IOException {
|
||||
try {
|
||||
|
||||
Object o;
|
||||
if( timeout == NO_WAIT_TIMEOUT ) {
|
||||
o = buffer.poll(0, TimeUnit.MILLISECONDS);
|
||||
} else if( timeout == WAIT_FOREVER_TIMEOUT ) {
|
||||
o = buffer.take();
|
||||
} else {
|
||||
o = buffer.poll(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if( o == null )
|
||||
return null;
|
||||
|
||||
if( o instanceof Packet )
|
||||
return (Packet)o;
|
||||
|
||||
Throwable e = (Throwable)o;
|
||||
throw (IOException)new IOException("Async error occurred: "+e).initCause(e);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedIOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Disposable#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
asyncChannel.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#start()
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
asyncChannel.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#stop(long)
|
||||
*/
|
||||
public void stop(long timeout) throws IOException {
|
||||
asyncChannel.stop(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.AsyncChannelListener#onPacket(org.activeio.Packet)
|
||||
*/
|
||||
public void onPacket(Packet packet) {
|
||||
try {
|
||||
buffer.put(packet);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.AsyncChannelListener#onPacketError(org.activeio.ChannelException)
|
||||
*/
|
||||
public void onPacketError(IOException error) {
|
||||
try {
|
||||
buffer.put(error);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
if( target.isAssignableFrom(getClass()) ) {
|
||||
return this;
|
||||
}
|
||||
return asyncChannel.getAdapter(target);
|
||||
}
|
||||
|
||||
public AsyncChannel getAsyncChannel() {
|
||||
return asyncChannel;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return asyncChannel.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.activeio.AsyncChannelFactory;
|
||||
import org.activeio.SyncChannel;
|
||||
import org.activeio.SyncChannelFactory;
|
||||
import org.activeio.SyncChannelServer;
|
||||
|
||||
/**
|
||||
* @version $Revision$
|
||||
*/
|
||||
final public class AsyncToSyncChannelFactory implements SyncChannelFactory {
|
||||
|
||||
private AsyncChannelFactory asyncChannelFactory;
|
||||
|
||||
static public SyncChannelFactory adapt(AsyncChannelFactory channelFactory ) {
|
||||
|
||||
// It might not need adapting
|
||||
if( channelFactory instanceof SyncChannelServer ) {
|
||||
return (SyncChannelFactory) channelFactory;
|
||||
}
|
||||
|
||||
// Can we just just undo the adaptor
|
||||
if( channelFactory.getClass() == SyncToAsyncChannelFactory.class ) {
|
||||
return ((SyncToAsyncChannelFactory)channelFactory).getSyncChannelFactory();
|
||||
}
|
||||
|
||||
return new AsyncToSyncChannelFactory((AsyncChannelFactory)channelFactory);
|
||||
}
|
||||
|
||||
|
||||
private AsyncToSyncChannelFactory(AsyncChannelFactory asyncChannelFactory) {
|
||||
this.asyncChannelFactory = asyncChannelFactory;
|
||||
}
|
||||
|
||||
public SyncChannel openSyncChannel(URI location) throws IOException {
|
||||
return AsyncToSyncChannel.adapt( asyncChannelFactory.openAsyncChannel(location) );
|
||||
}
|
||||
|
||||
public SyncChannelServer bindSyncChannel(URI location) throws IOException {
|
||||
return AsyncToSyncChannelServer.adapt(asyncChannelFactory.bindAsyncChannel(location));
|
||||
}
|
||||
|
||||
public AsyncChannelFactory getAsyncChannelFactory() {
|
||||
return asyncChannelFactory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.activeio.AcceptListener;
|
||||
import org.activeio.AsyncChannelServer;
|
||||
import org.activeio.Channel;
|
||||
import org.activeio.ChannelServer;
|
||||
import org.activeio.SyncChannelServer;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
|
||||
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Adapts a {@see org.activeio.AsyncChannelServer} so that it provides an
|
||||
* {@see org.activeio.SynchChannelServer} interface.
|
||||
*
|
||||
* This object buffers asynchronous accepts from the {@see org.activeio.AsyncChannelServer}
|
||||
* abs buffers them in a {@see edu.emory.mathcs.backport.java.util.concurrent.Channel} util the client accepts the
|
||||
* connection.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
final public class AsyncToSyncChannelServer implements SyncChannelServer, AcceptListener {
|
||||
|
||||
private final AsyncChannelServer asyncChannelServer;
|
||||
private final BlockingQueue acceptBuffer;
|
||||
|
||||
static public SyncChannelServer adapt(ChannelServer channel) {
|
||||
return adapt(channel, new LinkedBlockingQueue());
|
||||
}
|
||||
|
||||
static public SyncChannelServer adapt(ChannelServer channel, BlockingQueue upPacketChannel) {
|
||||
|
||||
// It might not need adapting
|
||||
if( channel instanceof SyncChannelServer ) {
|
||||
return (SyncChannelServer) channel;
|
||||
}
|
||||
|
||||
// Can we just just undo the adaptor
|
||||
if( channel.getClass() == SyncToAsyncChannel.class ) {
|
||||
return ((SyncToAsyncChannelServer)channel).getSynchChannelServer();
|
||||
}
|
||||
|
||||
return new AsyncToSyncChannelServer((AsyncChannelServer)channel, upPacketChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@see #adapt(ChannelServer)}
|
||||
*/
|
||||
public AsyncToSyncChannelServer(AsyncChannelServer asyncChannelServer) {
|
||||
this(asyncChannelServer,new LinkedBlockingQueue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@see #adapt(ChannelServer, edu.emory.mathcs.backport.java.util.concurrent.Channel)}
|
||||
*/
|
||||
public AsyncToSyncChannelServer(AsyncChannelServer asyncChannelServer, BlockingQueue acceptBuffer) {
|
||||
this.asyncChannelServer = asyncChannelServer;
|
||||
this.acceptBuffer=acceptBuffer;
|
||||
this.asyncChannelServer.setAcceptListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.SyncChannelServer#accept(long)
|
||||
*/
|
||||
public org.activeio.Channel accept(long timeout) throws IOException {
|
||||
try {
|
||||
|
||||
Object o;
|
||||
if( timeout == NO_WAIT_TIMEOUT ) {
|
||||
o = acceptBuffer.poll(0, TimeUnit.MILLISECONDS);
|
||||
} else if( timeout == WAIT_FOREVER_TIMEOUT ) {
|
||||
o = acceptBuffer.take();
|
||||
} else {
|
||||
o = acceptBuffer.poll(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if( o == null )
|
||||
return null;
|
||||
|
||||
if( o instanceof Channel )
|
||||
return (Channel)o;
|
||||
|
||||
Throwable e = (Throwable)o;
|
||||
throw (IOException)new IOException("Async error occurred: "+e).initCause(e);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedIOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see org.activeio.Disposable#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
asyncChannelServer.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#start()
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
asyncChannelServer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.Service#stop(long)
|
||||
*/
|
||||
public void stop(long timeout) throws IOException {
|
||||
asyncChannelServer.stop(timeout);
|
||||
}
|
||||
|
||||
public URI getBindURI() {
|
||||
return asyncChannelServer.getBindURI();
|
||||
}
|
||||
|
||||
public URI getConnectURI() {
|
||||
return asyncChannelServer.getConnectURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.AcceptListener#onAccept(org.activeio.Channel)
|
||||
*/
|
||||
public void onAccept(org.activeio.Channel channel) {
|
||||
try {
|
||||
acceptBuffer.put(channel);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.activeio.AcceptListener#onAcceptError(java.io.IOException)
|
||||
*/
|
||||
public void onAcceptError(IOException error) {
|
||||
try {
|
||||
acceptBuffer.put(error);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncChannelServer getAsyncChannelServer() {
|
||||
return asyncChannelServer;
|
||||
}
|
||||
|
||||
public Object getAdapter(Class target) {
|
||||
if( target.isAssignableFrom(getClass()) ) {
|
||||
return this;
|
||||
}
|
||||
return asyncChannelServer.getAdapter(target);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return asyncChannelServer.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2004 Hiram Chirino
|
||||
*
|
||||
* Licensed 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.activeio.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.activeio.InputStreamChannel;
|
||||
|
||||
/**
|
||||
* Provides an InputStream for a given InputStreamChannel.
|
||||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class InputStreamChannelToInputStream extends InputStream {
|
||||
|
||||
private final InputStreamChannel channel;
|
||||
|
||||
/**
|
||||
* @param channel
|
||||
*/
|
||||
public InputStreamChannelToInputStream(final InputStreamChannel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return channel.available();
|
||||
}
|
||||
|
||||
public synchronized void mark(int arg0) {
|
||||
channel.mark(arg0);
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return channel.markSupported();
|
||||
}
|
||||
|
||||
public int read(byte[] arg0) throws IOException {
|
||||
return channel.read(arg0);
|
||||
}
|
||||
|
||||
public synchronized void reset() throws IOException {
|
||||
channel.reset();
|
||||
}
|
||||
|
||||
public long skip(long arg0) throws IOException {
|
||||
return channel.skip(arg0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.InputStream#read()
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
return channel.read();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.InputStream#read(byte[], int, int)
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return channel.read(b,off,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.InputStream#close()
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
channel.dispose();
|
||||
super.close();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue