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:
James Strachan 2005-12-12 17:53:59 +00:00
commit 40a7d3b6ac
1565 changed files with 194375 additions and 0 deletions

20
LICENSE.txt Executable file
View File

@ -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.
*
**/

29
README.txt Executable file
View File

@ -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

15
activecluster/.classpath Normal file
View File

@ -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>

10
activecluster/.cvsignore Normal file
View File

@ -0,0 +1,10 @@
target
bin
*.log
junit*.properties
activecluster.iml
activecluster.ipr
activecluster.iws
ActiveMQ
classes
test-classes

18
activecluster/.project Normal file
View File

@ -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>

23
activecluster/README.txt Normal file
View File

@ -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

63
activecluster/maven.xml Normal file
View File

@ -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>

View File

@ -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

225
activecluster/project.xml Normal file
View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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!");
}
}

View File

@ -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 {
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,11 @@
<html>
<head>
</head>
<body>
<p>
Default implementation of ActiveCluster using standard JMS API to build the cluster.
</p>
</body>
</html>

View File

@ -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>

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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());
}
}
}

View File

@ -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();
}
}
}

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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..
}
}

View File

@ -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();
}
}

203
activeio/LICENSE.txt Normal file
View File

@ -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.

140
activeio/maven.xml Normal file
View File

@ -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>

View File

@ -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

294
activeio/project.xml Normal file
View File

@ -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>

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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{
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 {
}

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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) {
}
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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