Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 43127 invoked from network); 5 Jul 2007 12:56:01 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 5 Jul 2007 12:56:01 -0000 Received: (qmail 42065 invoked by uid 500); 5 Jul 2007 12:56:03 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 42020 invoked by uid 500); 5 Jul 2007 12:56:03 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 42009 invoked by uid 99); 5 Jul 2007 12:56:03 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Jul 2007 05:56:03 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Jul 2007 05:55:58 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 33A8B1A981D; Thu, 5 Jul 2007 05:55:38 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ ... Date: Thu, 05 Jul 2007 12:55:38 -0000 To: scm@geronimo.apache.org From: gdamour@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070705125538.33A8B1A981D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.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 listenerToWADIListener; + + public WADICluster(DispatcherHolder dispatcherHolder) { + if (null == dispatcherHolder) { + throw new IllegalArgumentException("dispatcherHolder is required"); + } + this.dispatcherHolder = dispatcherHolder; + + listenerToWADIListener = new IdentityHashMap(); + } + + 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 getRemoteNodes() { + Collection peers = cluster.getRemotePeers().values(); + Set 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 wrapAsNode(Collection peers) { + Set nodes = new HashSet(); + 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 existingNodes = wrapAsNode(existing); + listener.onListenerRegistration(WADICluster.this, existingNodes); + } + + public void onMembershipChanged(org.codehaus.wadi.group.Cluster cluster, Set joiners, Set leavers) { + Set joinerNodes = wrapAsNode(joiners); + Set 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 remotePeers = new HashMap(); + 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 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 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 existing = new HashSet(); + 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 joiners = new HashSet(); + joiners.add(new BasicNode("peer1")); + Set leavers = new HashSet(); + 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 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 existing); + + void onMembershipChanged(Cluster cluster, Set joiners, Set leavers); +}