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$ $Date$ 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 }