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    }