001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.clustering.wadi;
018
019 import java.util.Collection;
020 import java.util.HashSet;
021 import java.util.IdentityHashMap;
022 import java.util.Set;
023
024 import org.apache.geronimo.clustering.Cluster;
025 import org.apache.geronimo.clustering.ClusterListener;
026 import org.apache.geronimo.clustering.Node;
027 import org.apache.geronimo.gbean.GBeanInfo;
028 import org.apache.geronimo.gbean.GBeanInfoBuilder;
029 import org.apache.geronimo.gbean.GBeanLifecycle;
030 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
031 import org.codehaus.wadi.group.Peer;
032
033 /**
034 *
035 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
036 */
037 public class BasicWADICluster implements GBeanLifecycle, WADICluster {
038 private final Node node;
039 private final DispatcherHolder dispatcherHolder;
040 private final NodeFactory nodeFactory;
041 private final IdentityHashMap<Peer, Node> peerToNode;
042 private final IdentityHashMap<ClusterListener, org.codehaus.wadi.group.ClusterListener> listenerToWADIListener;
043
044 private org.codehaus.wadi.group.Cluster cluster;
045
046 public BasicWADICluster(Node node, DispatcherHolder dispatcherHolder) {
047 this(node, dispatcherHolder, new NodeProxyFactory());
048 }
049
050 public BasicWADICluster(Node node, DispatcherHolder dispatcherHolder, NodeFactory nodeFactory) {
051 if (null == node) {
052 throw new IllegalArgumentException("node is required");
053 } else if (null == dispatcherHolder) {
054 throw new IllegalArgumentException("dispatcherHolder is required");
055 }
056 this.node = node;
057 this.dispatcherHolder = dispatcherHolder;
058 this.nodeFactory = nodeFactory;
059
060 peerToNode = new IdentityHashMap<Peer, Node>();
061 listenerToWADIListener = new IdentityHashMap<ClusterListener, org.codehaus.wadi.group.ClusterListener>();
062 }
063
064 public void doStart() throws Exception {
065 cluster = dispatcherHolder.getDispatcher().getCluster();
066 }
067
068 public void doStop() throws Exception {
069 clearListeners();
070 }
071
072 public void doFail() {
073 clearListeners();
074 }
075
076 public org.codehaus.wadi.group.Cluster getCluster() {
077 return cluster;
078 }
079
080 public String getName() {
081 return cluster.getClusterName();
082 }
083
084 public Node getLocalNode() {
085 return node;
086 }
087
088 public Set<Node> getRemoteNodes() {
089 Collection<Peer> peers = cluster.getRemotePeers().values();
090 Set<Node> nodes = wrapAsNode(peers, false);
091 return nodes;
092 }
093
094 public void addClusterListener(ClusterListener listener) {
095 if (null == listener) {
096 throw new IllegalArgumentException("listener is required");
097 }
098 GeronimoClusterListenerAdaptor wadiListener = new GeronimoClusterListenerAdaptor(listener);
099 listenerToWADIListener.put(listener, wadiListener);
100 cluster.addClusterListener(wadiListener);
101 }
102
103 public void removeClusterListener(ClusterListener listener) {
104 org.codehaus.wadi.group.ClusterListener wadiListener = listenerToWADIListener.remove(listener);
105 if (null == wadiListener) {
106 throw new IllegalArgumentException(listener + " is not registered");
107 }
108 cluster.removeClusterListener(wadiListener);
109 }
110
111 protected void clearListeners() {
112 for (org.codehaus.wadi.group.ClusterListener wadiListener : listenerToWADIListener.values()) {
113 cluster.removeClusterListener(wadiListener);
114 }
115
116 listenerToWADIListener.clear();
117 }
118
119 protected Set<Node> wrapAsNode(Collection<Peer> peers, boolean remove) {
120 Set<Node> nodes = new HashSet<Node>();
121 for (Peer peer : peers) {
122 Node node = wrapAsNode(peer, remove);
123 nodes.add(node);
124 }
125 return nodes;
126 }
127
128 protected Node wrapAsNode(Peer peer, boolean remove) {
129 Node node;
130 synchronized (peerToNode) {
131 if (remove) {
132 node = peerToNode.remove(peer);
133 if (null == node) {
134 throw new AssertionError("no node mapped to peer");
135 }
136 } else {
137 node = peerToNode.get(peer);
138 if (null == node) {
139 node = newRemoteNode(peer);
140 peerToNode.put(peer, node);
141 }
142 }
143 }
144 return node;
145 }
146
147 protected Node newRemoteNode(Peer peer) {
148 return nodeFactory.newNode(cluster, peer);
149 }
150
151 protected class GeronimoClusterListenerAdaptor implements org.codehaus.wadi.group.ClusterListener {
152 private final ClusterListener listener;
153
154 public GeronimoClusterListenerAdaptor(ClusterListener listener) {
155 this.listener = listener;
156 }
157
158 public void onListenerRegistration(org.codehaus.wadi.group.Cluster cluster, Set existing) {
159 Set<Node> existingNodes = wrapAsNode(existing, false);
160 listener.onListenerRegistration(BasicWADICluster.this, existingNodes);
161 }
162
163 public void onMembershipChanged(org.codehaus.wadi.group.Cluster cluster, Set joiners, Set leavers) {
164 Set<Node> joinerNodes = wrapAsNode(joiners, false);
165 Set<Node> leaverNodes = wrapAsNode(leavers, true);
166 listener.onMembershipChanged(BasicWADICluster.this, joinerNodes, leaverNodes);
167 }
168
169 }
170
171 public static final GBeanInfo GBEAN_INFO;
172
173 public static final String GBEAN_REF_NODE = "Node";
174 public static final String GBEAN_REF_DISPATCHER_HOLDER = "DispatcherHolder";
175
176 static {
177 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Cluster",
178 BasicWADICluster.class,
179 NameFactory.GERONIMO_SERVICE);
180
181 infoBuilder.addReference(GBEAN_REF_NODE, Node.class, NameFactory.GERONIMO_SERVICE);
182 infoBuilder.addReference(GBEAN_REF_DISPATCHER_HOLDER, DispatcherHolder.class, NameFactory.GERONIMO_SERVICE);
183
184 infoBuilder.addInterface(Cluster.class);
185
186 infoBuilder.setConstructor(new String[] { GBEAN_REF_NODE, GBEAN_REF_DISPATCHER_HOLDER });
187
188 GBEAN_INFO = infoBuilder.getBeanInfo();
189 }
190
191 public static GBeanInfo getGBeanInfo() {
192 return GBEAN_INFO;
193 }
194
195 }