You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by gd...@apache.org on 2007/07/05 14:55:38 UTC
svn commit: r553487 - in /geronimo/server/trunk/modules:
geronimo-clustering-wadi/src/main/java/org/apache/geronimo/clustering/wadi/
geronimo-clustering-wadi/src/test/ geronimo-clustering-wadi/src/test/java/
geronimo-clustering-wadi/src/test/java/org/ ...
Author: gdamour
Date: Thu Jul 5 05:55:36 2007
New Revision: 553487
URL: http://svn.apache.org/viewvc?view=rev&rev=553487
Log:
Add Cluster and ClusterListener to the clustering API. Cluster represents a cluster, i.e. a set of Nodes. Clients
can register a ClusterListener with a Cluster to be notified when Nodes are joining or leaving the Cluster.
Provide a WADI implementation of these contracts.
Added:
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/main/java/org/apache/geronimo/clustering/wadi/WADICluster.java
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/wadi/
geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/wadi/WADIClusterTest.java
geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/Cluster.java
geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/ClusterListener.java
Modified:
geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/BasicNode.java
Added: geronimo/server/trunk/modules/geronimo-clustering-wadi/src/main/java/org/apache/geronimo/clustering/wadi/WADICluster.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-clustering-wadi/src/main/java/org/apache/geronimo/clustering/wadi/WADICluster.java?view=auto&rev=553487
==============================================================================
--- geronimo/server/trunk/modules/geronimo-clustering-wadi/src/main/java/org/apache/geronimo/clustering/wadi/WADICluster.java (added)
+++ geronimo/server/trunk/modules/geronimo-clustering-wadi/src/main/java/org/apache/geronimo/clustering/wadi/WADICluster.java Thu Jul 5 05:55:36 2007
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.clustering.wadi;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import org.apache.geronimo.clustering.BasicNode;
+import org.apache.geronimo.clustering.Cluster;
+import org.apache.geronimo.clustering.ClusterListener;
+import org.apache.geronimo.clustering.Node;
+import org.apache.geronimo.gbean.GBeanInfo;
+import org.apache.geronimo.gbean.GBeanInfoBuilder;
+import org.apache.geronimo.gbean.GBeanLifecycle;
+import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
+import org.codehaus.wadi.group.LocalPeer;
+import org.codehaus.wadi.group.Peer;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class WADICluster implements GBeanLifecycle, Cluster {
+ private final DispatcherHolder dispatcherHolder;
+ private org.codehaus.wadi.group.Cluster cluster;
+ private final IdentityHashMap<ClusterListener, org.codehaus.wadi.group.ClusterListener> listenerToWADIListener;
+
+ public WADICluster(DispatcherHolder dispatcherHolder) {
+ if (null == dispatcherHolder) {
+ throw new IllegalArgumentException("dispatcherHolder is required");
+ }
+ this.dispatcherHolder = dispatcherHolder;
+
+ listenerToWADIListener = new IdentityHashMap<ClusterListener, org.codehaus.wadi.group.ClusterListener>();
+ }
+
+ public void doStart() throws Exception {
+ cluster = dispatcherHolder.getDispatcher().getCluster();
+ }
+
+ public void doStop() throws Exception {
+ clearListeners();
+ }
+
+ public void doFail() {
+ clearListeners();
+ }
+
+ public String getName() {
+ return cluster.getClusterName();
+ }
+
+ public Node getLocalNode() {
+ LocalPeer localPeer = cluster.getLocalPeer();
+ return new BasicNode(localPeer.getName());
+ }
+
+ public Set<Node> getRemoteNodes() {
+ Collection<Peer> peers = cluster.getRemotePeers().values();
+ Set<Node> nodes = wrapAsNode(peers);
+ return nodes;
+ }
+
+ public void addClusterListener(ClusterListener listener) {
+ if (null == listener) {
+ throw new IllegalArgumentException("listener is required");
+ }
+ GeronimoClusterListenerAdaptor wadiListener = new GeronimoClusterListenerAdaptor(listener);
+ listenerToWADIListener.put(listener, wadiListener);
+ cluster.addClusterListener(wadiListener);
+ }
+
+ public void removeClusterListener(ClusterListener listener) {
+ org.codehaus.wadi.group.ClusterListener wadiListener = listenerToWADIListener.remove(listener);
+ if (null == wadiListener) {
+ throw new IllegalArgumentException(listener + " is not registered");
+ }
+ cluster.removeClusterListener(wadiListener);
+ }
+
+ protected void clearListeners() {
+ for (org.codehaus.wadi.group.ClusterListener wadiListener : listenerToWADIListener.values()) {
+ cluster.removeClusterListener(wadiListener);
+ }
+
+ listenerToWADIListener.clear();
+ }
+
+ protected Set<Node> wrapAsNode(Collection<Peer> peers) {
+ Set<Node> nodes = new HashSet<Node>();
+ for (Peer peer : peers) {
+ nodes.add(new BasicNode(peer.getName()));
+ }
+ return nodes;
+ }
+
+ protected class GeronimoClusterListenerAdaptor implements org.codehaus.wadi.group.ClusterListener {
+ private final ClusterListener listener;
+
+ public GeronimoClusterListenerAdaptor(ClusterListener listener) {
+ this.listener = listener;
+ }
+
+ public void onListenerRegistration(org.codehaus.wadi.group.Cluster cluster, Set existing) {
+ Set<Node> existingNodes = wrapAsNode(existing);
+ listener.onListenerRegistration(WADICluster.this, existingNodes);
+ }
+
+ public void onMembershipChanged(org.codehaus.wadi.group.Cluster cluster, Set joiners, Set leavers) {
+ Set<Node> joinerNodes = wrapAsNode(joiners);
+ Set<Node> leaverNodes = wrapAsNode(leavers);
+ listener.onMembershipChanged(WADICluster.this, joinerNodes, leaverNodes);
+ }
+
+ }
+
+ public static final GBeanInfo GBEAN_INFO;
+
+ public static final String GBEAN_REF_DISPATCHER_HOLDER = "DispatcherHolder";
+
+ static {
+ GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Cluster",
+ WADICluster.class,
+ NameFactory.GERONIMO_SERVICE);
+
+ infoBuilder.addReference(GBEAN_REF_DISPATCHER_HOLDER, DispatcherHolder.class, NameFactory.GERONIMO_SERVICE);
+
+ infoBuilder.addInterface(Cluster.class);
+
+ infoBuilder.setConstructor(new String[] {GBEAN_REF_DISPATCHER_HOLDER});
+
+ GBEAN_INFO = infoBuilder.getBeanInfo();
+ }
+
+ public static GBeanInfo getGBeanInfo() {
+ return GBEAN_INFO;
+ }
+
+}
Added: geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/wadi/WADIClusterTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/wadi/WADIClusterTest.java?view=auto&rev=553487
==============================================================================
--- geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/wadi/WADIClusterTest.java (added)
+++ geronimo/server/trunk/modules/geronimo-clustering-wadi/src/test/java/org/apache/geronimo/clustering/wadi/WADIClusterTest.java Thu Jul 5 05:55:36 2007
@@ -0,0 +1,245 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.clustering.wadi;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geronimo.clustering.BasicNode;
+import org.apache.geronimo.clustering.ClusterListener;
+import org.apache.geronimo.clustering.Node;
+import org.codehaus.wadi.group.Address;
+import org.codehaus.wadi.group.LocalPeer;
+import org.codehaus.wadi.group.Peer;
+
+import com.agical.rmock.core.Action;
+import com.agical.rmock.core.MethodHandle;
+import com.agical.rmock.core.describe.ExpressionDescriber;
+import com.agical.rmock.core.match.operator.AbstractExpression;
+import com.agical.rmock.extension.junit.RMockTestCase;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class WADIClusterTest extends RMockTestCase {
+
+ private org.codehaus.wadi.group.Cluster wadiCluster;
+ private LocalPeer localPeer;
+ private Peer peer1;
+ private Peer peer2;
+ private WADICluster cluster;
+ private ClusterListener listener;
+
+ @Override
+ protected void setUp() throws Exception {
+ DispatcherHolder dispatcherHolder = (DispatcherHolder) mock(DispatcherHolder.class);
+
+ wadiCluster = dispatcherHolder.getDispatcher().getCluster();
+ wadiCluster.getClusterName();
+ modify().multiplicity(expect.from(0)).returnValue("name");
+
+ localPeer = wadiCluster.getLocalPeer();
+ modify().multiplicity(expect.from(0));
+ localPeer.getName();
+ modify().multiplicity(expect.from(0)).returnValue("localPeerName");
+
+ Map<Address, Peer> remotePeers = new HashMap<Address, Peer>();
+ peer1 = addPeer("peer1", remotePeers);
+ peer2 = addPeer("peer2", remotePeers);
+
+ wadiCluster.getRemotePeers();
+ modify().multiplicity(expect.from(0)).returnValue(remotePeers);
+
+ cluster = new WADICluster(dispatcherHolder);
+ listener = (ClusterListener) mock(ClusterListener.class);
+ }
+
+ private Peer addPeer(String peerName, Map<Address, Peer> remotePeers) {
+ Peer peer = (Peer) mock(Peer.class, peerName);
+
+ Address address = peer.getAddress();
+ modify().multiplicity(expect.from(0));
+ peer.getName();
+ modify().multiplicity(expect.from(0)).returnValue(peerName);
+
+ remotePeers.put(address, peer);
+
+ return peer;
+ }
+
+ public void testGetName() throws Exception {
+ startVerification();
+ cluster.doStart();
+
+ assertEquals(wadiCluster.getClusterName(), cluster.getName());
+ }
+
+ public void testGetLocalNode() throws Exception {
+ startVerification();
+ cluster.doStart();
+
+ assertEquals(localPeer.getName(), cluster.getLocalNode().getName());
+ }
+
+ public void testGetRemotePeers() throws Exception {
+ startVerification();
+ cluster.doStart();
+
+ Set<Node> remoteNodes = cluster.getRemoteNodes();
+ assertEquals(2, remoteNodes.size());
+ assertTrue(remoteNodes.contains(new BasicNode(peer1.getName())));
+ assertTrue(remoteNodes.contains(new BasicNode(peer2.getName())));
+ }
+
+ public void testAddClusterListener() throws Exception {
+ wadiCluster.addClusterListener(null);
+ modify().args(new AbstractExpression() {
+
+ public void describeWith(ExpressionDescriber arg0) throws IOException {
+ }
+
+ public boolean passes(Object arg0) {
+ assertTrue(arg0 instanceof org.codehaus.wadi.group.ClusterListener);
+ return true;
+ }
+
+ });
+
+ startVerification();
+ cluster.doStart();
+
+ cluster.addClusterListener(listener);
+ }
+
+ public void testAddNullClusterListenerThrowsException() throws Exception {
+ startVerification();
+ cluster.doStart();
+
+ try {
+ cluster.addClusterListener(null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testRemoveClusterListener() throws Exception {
+ AbstractExpression assertSame = new AssertSameWADIListener();
+ wadiCluster.addClusterListener(null);
+ modify().args(assertSame);
+ wadiCluster.removeClusterListener(null);
+ modify().args(assertSame);
+
+ startVerification();
+ cluster.doStart();
+
+ cluster.addClusterListener(listener);
+ cluster.removeClusterListener(listener);
+ }
+
+ public void testRemoveUndefinedClusterListenerThrowsException() throws Exception {
+ startVerification();
+ cluster.doStart();
+
+ try {
+ cluster.removeClusterListener(listener);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testClusterListenerRegistrationCallback() throws Exception {
+ Set<Node> existing = new HashSet<Node>();
+ existing.add(new BasicNode("peer1"));
+ listener.onListenerRegistration(cluster, existing);
+
+ wadiCluster.addClusterListener(null);
+ modify().args(is.ANYTHING).perform(new Action() {
+
+ public Object invocation(Object[] arg0, MethodHandle arg1) throws Throwable {
+ org.codehaus.wadi.group.ClusterListener wadiListener = (org.codehaus.wadi.group.ClusterListener) arg0[0];
+ wadiListener.onListenerRegistration(wadiCluster, Collections.singleton(peer1));;
+ return null;
+ }
+
+ });
+
+ startVerification();
+ cluster.doStart();
+
+ cluster.addClusterListener(listener);
+ }
+
+ public void testClusterListenerMembershipChangeCallback() throws Exception {
+ Set<Node> joiners = new HashSet<Node>();
+ joiners.add(new BasicNode("peer1"));
+ Set<Node> leavers = new HashSet<Node>();
+ leavers.add(new BasicNode("peer2"));
+ listener.onMembershipChanged(cluster, joiners, leavers);
+
+ wadiCluster.addClusterListener(null);
+ modify().args(is.ANYTHING).perform(new Action() {
+
+ public Object invocation(Object[] arg0, MethodHandle arg1) throws Throwable {
+ org.codehaus.wadi.group.ClusterListener wadiListener = (org.codehaus.wadi.group.ClusterListener) arg0[0];
+ wadiListener.onMembershipChanged(wadiCluster, Collections.singleton(peer1), Collections.singleton(peer2));
+ return null;
+ }
+
+ });
+
+ startVerification();
+ cluster.doStart();
+
+ cluster.addClusterListener(listener);
+ }
+
+ public void testRemoveListenersOnStopOrFail() throws Exception {
+ AbstractExpression assertSame = new AssertSameWADIListener();
+ wadiCluster.addClusterListener(null);
+ modify().args(assertSame);
+ wadiCluster.removeClusterListener(null);
+ modify().args(assertSame);
+
+ startVerification();
+ cluster.doStart();
+
+ cluster.addClusterListener(listener);
+ cluster.doStop();
+ }
+
+ private final class AssertSameWADIListener extends AbstractExpression {
+ private org.codehaus.wadi.group.ClusterListener wadiListener;
+
+ public void describeWith(ExpressionDescriber arg0) throws IOException {
+ }
+
+ public boolean passes(Object arg0) {
+ if (null == wadiListener) {
+ wadiListener = (org.codehaus.wadi.group.ClusterListener) arg0;
+ } else {
+ assertSame(wadiListener, arg0);
+ }
+ return true;
+ }
+ }
+
+}
Modified: geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/BasicNode.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/BasicNode.java?view=diff&rev=553487&r1=553486&r2=553487
==============================================================================
--- geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/BasicNode.java (original)
+++ geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/BasicNode.java Thu Jul 5 05:55:36 2007
@@ -28,11 +28,28 @@
private final String name;
public BasicNode(String name) {
+ if (null == name) {
+ throw new IllegalArgumentException("name is required");
+ }
this.name = name;
}
public String getName() {
return name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BasicNode)) {
+ return false;
+ }
+ BasicNode other = (BasicNode) obj;
+ return name.equals(other.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
}
public static final GBeanInfo GBEAN_INFO;
Added: geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/Cluster.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/Cluster.java?view=auto&rev=553487
==============================================================================
--- geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/Cluster.java (added)
+++ geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/Cluster.java Thu Jul 5 05:55:36 2007
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.clustering;
+
+import java.util.Set;
+
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public interface Cluster {
+ String getName();
+
+ Node getLocalNode();
+
+ Set<Node> getRemoteNodes();
+
+ void addClusterListener(ClusterListener listener);
+
+ void removeClusterListener(ClusterListener listener);
+}
Added: geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/ClusterListener.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/ClusterListener.java?view=auto&rev=553487
==============================================================================
--- geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/ClusterListener.java (added)
+++ geronimo/server/trunk/modules/geronimo-clustering/src/main/java/org/apache/geronimo/clustering/ClusterListener.java Thu Jul 5 05:55:36 2007
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.clustering;
+
+import java.util.Set;
+
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public interface ClusterListener {
+ void onListenerRegistration(Cluster cluster, Set<Node> existing);
+
+ void onMembershipChanged(Cluster cluster, Set<Node> joiners, Set<Node> leavers);
+}