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 2008/02/23 02:03:09 UTC

svn commit: r630370 [3/4] - in /geronimo/server/trunk: ./ assemblies/geronimo-jetty6-javaee5/ framework/modules/geronimo-kernel/src/test/java/org/apache/geronimo/kernel/config/ plugins/clustering/geronimo-clustering-wadi/src/main/java/org/apache/geroni...

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTracker.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTracker.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTracker.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTracker.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,108 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class BasicNetworkConnectorTracker implements NetworkConnectorTracker {
+    private final Map<Object, Set<URI>> idToLocations;
+    private final Map<String, Set<URI>> nodeNameToLocations;
+    
+    public BasicNetworkConnectorTracker() {
+        idToLocations = new HashMap<Object, Set<URI>>();
+        nodeNameToLocations = new HashMap<String, Set<URI>>();
+    }
+
+    public Set<URI> getConnectorURIs(Object deploymentId) throws NetworkConnectorTrackerException {
+        Set<URI> locations;
+        synchronized (idToLocations) {
+            locations = idToLocations.get(deploymentId);
+            if (null == locations) {
+                throw new NetworkConnectorTrackerException("[" + deploymentId + "] is not registered");
+            }
+            locations = new HashSet<URI>(locations);
+        }
+        return locations;
+    }
+
+    public void registerNetworkConnectorLocations(Object deploymentId, String nodeName, Set<URI> locations) {
+        synchronized (idToLocations) {
+            Set<URI> allLocations = idToLocations.get(deploymentId);
+            if (null == allLocations) {
+                allLocations = new HashSet<URI>();
+                idToLocations.put(deploymentId, allLocations);
+            }
+            allLocations.addAll(locations);
+            
+            allLocations = nodeNameToLocations.get(nodeName);
+            if (null == allLocations) {
+                allLocations = new HashSet<URI>();
+                nodeNameToLocations.put(nodeName, allLocations);
+            }
+            allLocations.addAll(locations);
+        }
+    }
+
+    public void unregisterNetworkConnectorLocations(Object deploymentId, String nodeName, Set<URI> locations) {
+        synchronized (idToLocations) {
+            Set<URI> allLocations = idToLocations.get(deploymentId);
+            if (null == allLocations) {
+                return;
+            }
+            allLocations.removeAll(locations);
+            if (allLocations.isEmpty()) {
+                idToLocations.remove(deploymentId);
+            }
+            
+            allLocations = nodeNameToLocations.get(nodeName);
+            allLocations.removeAll(locations);
+            if (allLocations.isEmpty()) {
+                nodeNameToLocations.remove(nodeName);
+            }
+        }
+    }
+
+    public void unregisterNetworkConnectorLocations(String nodeName) {
+        synchronized (idToLocations) {
+            Set<URI> locationsToRemove = nodeNameToLocations.remove(nodeName);
+            if (null == locationsToRemove) {
+                return;
+            }
+            Map<Object, Set<URI>> clonedIdToLocations = new HashMap<Object, Set<URI>>(idToLocations);
+            for (Map.Entry<Object, Set<URI>> entry : clonedIdToLocations.entrySet()) {
+                Set<URI> allLocations = entry.getValue();
+                allLocations.removeAll(locationsToRemove);
+                if (allLocations.isEmpty()) {
+                    idToLocations.remove(entry.getKey());
+                }
+            }
+        }
+    }
+    
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerServiceHolder.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerServiceHolder.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerServiceHolder.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerServiceHolder.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,58 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import org.apache.geronimo.clustering.wadi.ClusteredServiceHolder;
+import org.apache.geronimo.gbean.GBeanInfo;
+import org.apache.geronimo.gbean.GBeanInfoBuilder;
+import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
+import org.codehaus.wadi.servicespace.ServiceName;
+
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class BasicNetworkConnectorTrackerServiceHolder implements ClusteredServiceHolder {
+    
+    public Object getService() {
+        return new BasicNetworkConnectorTracker();
+    }
+
+    public ServiceName getServiceName() {
+        return NetworkConnectorTracker.NAME;
+    }
+
+    public static final GBeanInfo GBEAN_INFO;
+
+    static {
+        GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("NetworkConnectorTracker ClusteredServiceHolder",
+            BasicNetworkConnectorTrackerServiceHolder.class, NameFactory.GERONIMO_SERVICE);
+
+        infoBuilder.setConstructor(new String[0]);
+
+        GBEAN_INFO = infoBuilder.getBeanInfo();
+    }
+
+    public static GBeanInfo getGBeanInfo() {
+        return GBEAN_INFO;
+    }
+    
+}
\ No newline at end of file

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitor.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitor.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitor.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitor.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,287 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.clustering.Node;
+import org.apache.geronimo.clustering.SessionManagerListener;
+import org.apache.geronimo.clustering.wadi.RemoteNode;
+import org.apache.geronimo.clustering.wadi.WADISessionManager;
+import org.apache.geronimo.gbean.GBeanInfo;
+import org.apache.geronimo.gbean.GBeanInfoBuilder;
+import org.apache.geronimo.gbean.GBeanLifecycle;
+import org.apache.geronimo.gbean.ReferenceCollection;
+import org.apache.geronimo.gbean.ReferenceCollectionEvent;
+import org.apache.geronimo.gbean.ReferenceCollectionListener;
+import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
+import org.apache.geronimo.management.geronimo.NetworkConnector;
+import org.apache.geronimo.openejb.EjbDeploymentIdAccessor;
+import org.codehaus.wadi.group.Peer;
+import org.codehaus.wadi.servicespace.InvocationMetaData;
+import org.codehaus.wadi.servicespace.ServiceNotAvailableException;
+import org.codehaus.wadi.servicespace.ServiceNotFoundException;
+import org.codehaus.wadi.servicespace.ServiceProxy;
+import org.codehaus.wadi.servicespace.ServiceProxyFactory;
+import org.codehaus.wadi.servicespace.ServiceRegistry;
+import org.codehaus.wadi.servicespace.ServiceSpace;
+
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class NetworkConnectorMonitor implements GBeanLifecycle {
+    private static final Log log = LogFactory.getLog(NetworkConnectorMonitor.class);
+    
+    private final Collection<NetworkConnector> connectors;
+    private final Collection<EjbDeploymentIdAccessor> idAccessors;
+    private final WADISessionManager sessionManager;
+    private final String nodeName;
+    private final Set<URI> locations;
+    private NetworkConnectorTracker localTracker;
+    private ServiceProxyFactory trackerProxyFactory;
+    
+    public NetworkConnectorMonitor(Collection<NetworkConnector> connectors,
+        Collection<EjbDeploymentIdAccessor> idAccessors,
+        WADISessionManager sessionManager) {
+        if (null == connectors && !(connectors instanceof ReferenceCollection)) {
+            throw new IllegalArgumentException("connectors must be a [" + ReferenceCollection.class + "]");
+        } else if (null == idAccessors && !(idAccessors instanceof ReferenceCollection)) {
+            throw new IllegalArgumentException("idAccessors must be a [" + ReferenceCollection.class + "]");
+        } else if (null == sessionManager) {
+            throw new IllegalArgumentException("sessionManager is required");
+        }
+        this.connectors = connectors;
+        this.idAccessors = idAccessors;
+        this.sessionManager = sessionManager;
+        
+        nodeName = sessionManager.getCluster().getLocalNode().getName();
+        
+        locations = new HashSet<URI>();
+
+        registerListenerForMembershipUpdates(sessionManager);
+        registerListenerForConnectorUpdates((ReferenceCollection) connectors);
+        registerListenerForDeploymentUpdates((ReferenceCollection) idAccessors);
+    }
+
+    protected void registerListenerForMembershipUpdates(WADISessionManager sessionManager) {
+        sessionManager.registerSessionManagerListener(new SessionManagerListener() {
+            public void onJoin(Node joiningNode, Set<Node> newHostingNodes) {
+                Set<URI> clonedLocations;
+                synchronized (locations) {
+                    clonedLocations = new HashSet<URI>(locations);
+                }
+                for (EjbDeploymentIdAccessor deploymentIdAccessor : NetworkConnectorMonitor.this.idAccessors) {
+                    String deploymentId = deploymentIdAccessor.getDeploymentId();
+                    ServiceProxy proxy = trackerProxyFactory.getProxy();
+                    RemoteNode remoteNode = (RemoteNode) joiningNode;
+                    proxy.getInvocationMetaData().setTargets(new Peer[] {remoteNode.getPeer()});
+                    NetworkConnectorTracker tracker = (NetworkConnectorTracker)  proxy;
+                    tracker.registerNetworkConnectorLocations(deploymentId, nodeName, clonedLocations);
+                }
+            }
+
+            public void onLeave(Node leavingNode, Set<Node> newHostingNodes) {
+                String leavingNodeName = leavingNode.getName();
+                localTracker.unregisterNetworkConnectorLocations(leavingNodeName);
+            }
+        });
+    }
+
+    protected void registerListenerForDeploymentUpdates(ReferenceCollection deploymentIdAccessors) {
+        deploymentIdAccessors.addReferenceCollectionListener(new ReferenceCollectionListener() {
+            public void memberAdded(ReferenceCollectionEvent event) {
+                EjbDeploymentIdAccessor idAccessor = (EjbDeploymentIdAccessor) event.getMember();
+                String deploymentId = idAccessor.getDeploymentId();
+                updateTracker(deploymentId);
+            }
+
+            public void memberRemoved(ReferenceCollectionEvent event) {
+                EjbDeploymentIdAccessor idAccessor = (EjbDeploymentIdAccessor) event.getMember();
+                String deploymentId = idAccessor.getDeploymentId();
+                removeTracker(deploymentId);
+            }
+        });
+    }
+
+    protected void registerListenerForConnectorUpdates(ReferenceCollection connectors) {
+        connectors.addReferenceCollectionListener(new ReferenceCollectionListener() {
+            public void memberAdded(ReferenceCollectionEvent event) {
+                URI uri = buildURI(event);
+                synchronized (locations) {
+                    locations.add(uri);
+                }
+                Set<URI> uris = new HashSet<URI>();
+                uris.add(uri);
+                for (EjbDeploymentIdAccessor deploymentIdAccessor : idAccessors) {
+                    String deploymentId = deploymentIdAccessor.getDeploymentId();
+                    updateTracker(deploymentId, uris);
+                }
+            }
+
+            public void memberRemoved(ReferenceCollectionEvent event) {
+                URI uri = buildURI(event);
+                synchronized (locations) {
+                    locations.remove(uri);
+                }
+                Set<URI> uris = new HashSet<URI>();
+                uris.add(uri);
+                for (EjbDeploymentIdAccessor deploymentIdAccessor : idAccessors) {
+                    String deploymentId = deploymentIdAccessor.getDeploymentId();
+                    removeTracker(deploymentId, uris);
+                }
+            }
+
+            protected URI buildURI(ReferenceCollectionEvent event) {
+                NetworkConnector connector = (NetworkConnector) event.getMember();
+                return NetworkConnectorMonitor.this.buildURI(connector);
+            }
+        });
+    }
+
+    public void doFail() {
+        try {
+            doStop();
+        } catch (Exception e) {
+            log.error("See nested", e);
+        }
+    }
+
+    public void doStart() throws Exception {
+        trackerProxyFactory = newNetworkConnectorTrackerProxy();
+        
+        localTracker = locateLocalNetworkConnectorTracker();
+
+        for (NetworkConnector connector : connectors) {
+            URI uri = buildURI(connector);
+            synchronized (locations) {
+                locations.add(uri);
+            }
+        }
+
+        for (EjbDeploymentIdAccessor deploymentIdAccessor : idAccessors) {
+            String deploymentId = deploymentIdAccessor.getDeploymentId();
+            updateTracker(deploymentId);
+        }
+    }
+
+    public void doStop() throws Exception {
+        synchronized (locations) {
+            locations.clear();
+        }
+    }
+
+    protected NetworkConnectorTracker locateLocalNetworkConnectorTracker() {
+        ServiceSpace serviceSpace = sessionManager.getServiceSpace();
+        ServiceRegistry serviceRegistry = serviceSpace.getServiceRegistry();
+        try {
+            return (NetworkConnectorTracker) serviceRegistry.getStartedService(NetworkConnectorTracker.NAME);
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+    
+    protected URI buildURI(NetworkConnector connector) {
+        String uriAsString = connector.getProtocol() + "://" + connector.getHost() + ":" + connector.getPort();
+        URI uri;
+        try {
+            uri = new URI(uriAsString);
+        } catch (URISyntaxException e) {
+            throw new IllegalStateException("URI [" + uriAsString + "] is invalid", e);
+        }
+        return uri;
+    }
+
+    protected ServiceProxyFactory newNetworkConnectorTrackerProxy() {
+        ServiceSpace serviceSpace = sessionManager.getServiceSpace();
+        ServiceProxyFactory proxyFactory = serviceSpace.getServiceProxyFactory(NetworkConnectorTracker.NAME,
+            new Class[] { NetworkConnectorTracker.class });
+        InvocationMetaData invocationMetaData = proxyFactory.getInvocationMetaData();
+        invocationMetaData.setOneWay(true);
+        return proxyFactory;
+    }
+
+    protected void updateTrackerForAllDeploymentIds() {
+        for (EjbDeploymentIdAccessor deploymentIdAccessor : idAccessors) {
+            String deploymentId = deploymentIdAccessor.getDeploymentId();
+            updateTracker(deploymentId);
+        }
+    }
+
+    protected void updateTracker(Object deploymentId) {
+        Set<URI> clonedLocations;
+        synchronized (locations) {
+            clonedLocations = new HashSet<URI>(locations);
+        }
+        updateTracker(deploymentId, clonedLocations);
+    }
+    
+    protected void updateTracker(Object deploymentId, Set<URI> locationsToRegister) {
+        NetworkConnectorTracker tracker = (NetworkConnectorTracker) trackerProxyFactory.getProxy();
+        tracker.registerNetworkConnectorLocations(deploymentId, nodeName, locationsToRegister);
+    }
+    
+    protected void removeTracker(Object deploymentId) {
+        Set<URI> clonedLocations;
+        synchronized (locations) {
+            clonedLocations = new HashSet<URI>(locations);
+        }
+        removeTracker(deploymentId, clonedLocations);
+    }
+
+    protected void removeTracker(Object deploymentId, Set<URI> locationsToUnregister) {
+        NetworkConnectorTracker tracker = (NetworkConnectorTracker) trackerProxyFactory.getProxy();
+        tracker.unregisterNetworkConnectorLocations(deploymentId, nodeName, locationsToUnregister);
+    }
+    
+    public static final GBeanInfo GBEAN_INFO;
+
+    public static final String GBEAN_REF_NETWORK_CONNECTORS = "NetworkConnectors";
+    public static final String GBEAN_REF_EJB_DEP_ID_ACCESSOR = "EjbDeploymentIdAccessor";
+    public static final String GBEAN_REF_WADI_SESSION_MANAGER = "WADISessionManager";
+
+    static {
+        GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("NetworkConnectorMonitor",
+            NetworkConnectorMonitor.class,
+            NameFactory.GERONIMO_SERVICE);
+
+        infoBuilder.addReference(GBEAN_REF_NETWORK_CONNECTORS, NetworkConnector.class, NameFactory.GERONIMO_SERVICE);
+        infoBuilder.addReference(GBEAN_REF_EJB_DEP_ID_ACCESSOR, EjbDeploymentIdAccessor.class, NameFactory.GERONIMO_SERVICE);
+        infoBuilder.addReference(GBEAN_REF_WADI_SESSION_MANAGER, WADISessionManager.class, NameFactory.GERONIMO_SERVICE);
+
+        infoBuilder.setConstructor(new String[] {GBEAN_REF_NETWORK_CONNECTORS,
+            GBEAN_REF_EJB_DEP_ID_ACCESSOR,
+            GBEAN_REF_WADI_SESSION_MANAGER});
+
+        GBEAN_INFO = infoBuilder.getBeanInfo();
+    }
+
+    public static GBeanInfo getGBeanInfo() {
+        return GBEAN_INFO;
+    }
+
+}
\ No newline at end of file

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTracker.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTracker.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTracker.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTracker.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,41 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.codehaus.wadi.servicespace.ServiceName;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public interface NetworkConnectorTracker {
+    ServiceName NAME = new ServiceName("NetworkConnectorTracker");
+
+    Set<URI> getConnectorURIs(Object deploymentId) throws NetworkConnectorTrackerException;
+    
+    void registerNetworkConnectorLocations(Object deploymentId, String nodeName, Set<URI> locations);
+    
+    void unregisterNetworkConnectorLocations(Object deploymentId, String nodeName, Set<URI> locations);
+
+    void unregisterNetworkConnectorLocations(String nodeName);
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTrackerException.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTrackerException.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTrackerException.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorTrackerException.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,40 @@
+/*
+ * 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.openejb.cluster.infra;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class NetworkConnectorTrackerException extends Exception {
+
+    public NetworkConnectorTrackerException(Throwable throwable) {
+        super(throwable);
+    }
+    
+    public NetworkConnectorTrackerException(String message) {
+        super(message);
+    }
+
+    public NetworkConnectorTrackerException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+    
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/SessionManagerTracker.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/SessionManagerTracker.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/SessionManagerTracker.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/infra/SessionManagerTracker.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,32 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import org.apache.geronimo.clustering.SessionManager;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public interface SessionManagerTracker {
+    void addSessionManager(Object deploymentId, SessionManager sessionManager);
+
+    void removeSessionManager(Object deploymentId, SessionManager sessionManager);
+}
\ No newline at end of file

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredBeanEntry.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredBeanEntry.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredBeanEntry.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredBeanEntry.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,77 @@
+/*
+ * 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.openejb.cluster.stateful.container;
+
+import org.apache.geronimo.clustering.Session;
+import org.apache.openejb.core.stateful.BeanEntry;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class ClusteredBeanEntry extends BeanEntry {
+    protected static final String SESSION_KEY_ENTRY = "entry";
+
+    private transient final Session session;
+    private final Object deploymentId;
+
+    protected static ClusteredBeanEntry getEntry(Session session) {
+        if (null == session) {
+            throw new IllegalArgumentException("session is required");
+        }
+        return (ClusteredBeanEntry) session.getState(SESSION_KEY_ENTRY);
+    }
+
+    protected ClusteredBeanEntry(Session session,
+        Object deploymentId,
+        Object beanInstance,
+        Object primaryKey,
+        long timeOut) {
+        super(beanInstance, primaryKey, timeOut);
+        if (null == session) {
+            throw new IllegalArgumentException("session is required");
+        } else if (null == deploymentId) {
+            throw new IllegalArgumentException("deploymentId is required");
+        }
+        this.session = session;
+        this.deploymentId = deploymentId;
+        
+        session.addState(SESSION_KEY_ENTRY, this);
+    }
+
+    protected ClusteredBeanEntry(Session session) {
+        super(getEntry(session));
+        this.session = session;
+        this.deploymentId = getEntry(session).deploymentId;
+    }
+
+    public void release() {
+        session.release();
+    }
+
+    public void endAccess() {
+        session.onEndAccess();
+    }
+    
+    public Object getDeploymentId() {
+        return deploymentId;
+    }
+
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulContainer.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulContainer.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulContainer.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulContainer.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,291 @@
+/*
+ * 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.openejb.cluster.stateful.container;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.geronimo.clustering.SessionManager;
+import org.apache.geronimo.clustering.wadi.WADISessionManager;
+import org.apache.geronimo.openejb.cluster.infra.NetworkConnectorTracker;
+import org.apache.geronimo.openejb.cluster.infra.NetworkConnectorTrackerException;
+import org.apache.geronimo.openejb.cluster.infra.SessionManagerTracker;
+import org.apache.openejb.ClusteredRPCContainer;
+import org.apache.openejb.DeploymentInfo;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.core.CoreDeploymentInfo;
+import org.apache.openejb.core.stateful.StatefulContainer;
+import org.apache.openejb.spi.SecurityService;
+import org.codehaus.wadi.core.contextualiser.BasicInvocation;
+import org.codehaus.wadi.core.contextualiser.InvocationContext;
+import org.codehaus.wadi.core.contextualiser.InvocationException;
+import org.codehaus.wadi.core.manager.Manager;
+import org.codehaus.wadi.servicespace.ServiceRegistry;
+import org.codehaus.wadi.servicespace.ServiceSpace;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class ClusteredStatefulContainer extends StatefulContainer implements SessionManagerTracker, ClusteredRPCContainer {
+    private final Map<Object, Manager> deploymentIdToManager;
+    private final Map<Object, NetworkConnectorTracker> deploymentIdToNetworkConnectorTracker;
+    
+    public ClusteredStatefulContainer(Object id,
+        TransactionManager transactionManager,
+        SecurityService securityService,
+        Class passivator,
+        int timeOut,
+        int poolSize,
+        int bulkPassivate) throws OpenEJBException {
+        super(id, transactionManager, securityService, passivator, timeOut, poolSize, bulkPassivate);
+        
+        deploymentIdToManager = new HashMap<Object, Manager>();
+        deploymentIdToNetworkConnectorTracker = new HashMap<Object, NetworkConnectorTracker>();
+    }
+
+    @Override
+    protected ClusteredStatefulInstanceManager newStatefulInstanceManager(TransactionManager transactionManager,
+        SecurityService securityService,
+        Class passivator,
+        int timeOut,
+        int poolSize,
+        int bulkPassivate) throws OpenEJBException {
+        return new ClusteredStatefulInstanceManager(transactionManager,
+            securityService,
+            entityManagerRegistry,
+            passivator,
+            timeOut,
+            poolSize,
+            bulkPassivate);
+    }
+
+    public void addSessionManager(Object deploymentId, SessionManager sessionManager) {
+        ((ClusteredStatefulInstanceManager) instanceManager).addSessionManager(deploymentId, sessionManager);
+        
+        WADISessionManager wadiSessionManager = (WADISessionManager) sessionManager;
+        
+        Manager manager = wadiSessionManager.getManager();
+        synchronized (deploymentIdToManager) {
+            deploymentIdToManager.put(deploymentId, manager);
+        }
+
+        ServiceSpace serviceSpace = wadiSessionManager.getServiceSpace();
+        ServiceRegistry serviceRegistry = serviceSpace.getServiceRegistry();
+        NetworkConnectorTracker networkConnectorTracker;
+        try {
+            networkConnectorTracker = (NetworkConnectorTracker) serviceRegistry.getStartedService(NetworkConnectorTracker.NAME);
+        } catch (Exception e) {
+            throw new IllegalStateException("Should never occur" ,e);
+        }
+        synchronized (deploymentIdToNetworkConnectorTracker) {
+            deploymentIdToNetworkConnectorTracker.put(deploymentId, networkConnectorTracker);   
+        }
+    }
+
+    public void removeSessionManager(Object deploymentId, SessionManager sessionManager) {
+        ((ClusteredStatefulInstanceManager) instanceManager).removeSessionManager(deploymentId, sessionManager);
+        
+        synchronized (deploymentIdToManager) {
+            deploymentIdToManager.remove(deploymentId);
+        }
+        synchronized (deploymentIdToNetworkConnectorTracker) {
+            deploymentIdToNetworkConnectorTracker.remove(deploymentId);
+        }
+    }
+    
+    public URI[] getLocations(DeploymentInfo deploymentInfo) {
+        Object deploymentID = deploymentInfo.getDeploymentID();
+        NetworkConnectorTracker networkConnectorTracker;
+        synchronized (deploymentIdToNetworkConnectorTracker) {
+            networkConnectorTracker = deploymentIdToNetworkConnectorTracker.get(deploymentID);
+        }
+        if (null == networkConnectorTracker) {
+            return null;
+        }
+
+        Set<URI> connectorURIs;
+        try {
+            connectorURIs = networkConnectorTracker.getConnectorURIs(deploymentID);
+        } catch (NetworkConnectorTrackerException e) {
+            return null;
+        }
+        return connectorURIs.toArray(new URI[0]);
+    }
+
+    @Override
+    protected Object businessMethod(CoreDeploymentInfo deploymentInfo,
+        Object primKey,
+        Class callInterface,
+        Method callMethod,
+        Object[] args) throws OpenEJBException {
+        AbstractEJBInvocation invocation = new BusinessMethodInvocation(primKey.toString(),
+            5000,
+            deploymentInfo,
+            primKey,
+            callInterface,
+            callMethod,
+            args);
+        return invoke(deploymentInfo, invocation);
+    }
+
+    protected Object superBusinessMethod(CoreDeploymentInfo deploymentInfo,
+        Object primKey,
+        Class callInterface,
+        Method callMethod,
+        Object[] args) throws OpenEJBException {
+        return super.businessMethod(deploymentInfo, primKey, callInterface, callMethod, args);
+    }
+    
+    @Override
+    protected Object removeEJBObject(CoreDeploymentInfo deploymentInfo,
+        Object primKey,
+        Class callInterface,
+        Method callMethod,
+        Object[] args) throws OpenEJBException {
+        AbstractEJBInvocation invocation = new RemoveEJBObjectInvocation(primKey.toString(),
+            5000,
+            deploymentInfo,
+            primKey,
+            callInterface,
+            callMethod,
+            args);
+        return invoke(deploymentInfo, invocation);
+    }
+
+    protected Object superRemoveEJBObject(CoreDeploymentInfo deploymentInfo,
+        Object primKey,
+        Class callInterface,
+        Method callMethod,
+        Object[] args) throws OpenEJBException {
+        return super.removeEJBObject(deploymentInfo, primKey, callInterface, callMethod, args);
+    }
+
+    protected Object invoke(CoreDeploymentInfo deploymentInfo, AbstractEJBInvocation invocation)
+            throws OpenEJBException {
+        Manager manager;
+        synchronized (deploymentIdToManager) {
+            manager = deploymentIdToManager.get(deploymentInfo.getDeploymentID());
+        }
+        if (null == manager) {
+            throw new OpenEJBException("No manager registered for [" + deploymentInfo + "]");
+        }
+        try {
+            manager.contextualise(invocation);
+        } catch (InvocationException e) {
+            Throwable throwable = e.getCause();
+            if (throwable instanceof OpenEJBException) {
+                throw (OpenEJBException) throwable;
+            } else {
+                throw new OpenEJBException(e);
+            }
+        }
+        return invocation.getResult();
+    }
+    
+    protected abstract class AbstractEJBInvocation extends BasicInvocation {
+        protected final CoreDeploymentInfo deploymentInfo;
+        protected final Object primKey;
+        protected final Class callInterface;
+        protected final Method callMethod;
+        protected final Object[] args;
+        protected Object result;
+
+        protected AbstractEJBInvocation(String sessionKey,
+            long exclusiveSessionLockWaitTime,
+            CoreDeploymentInfo deploymentInfo,
+            Object primKey,
+            Class callInterface,
+            Method callMethod,
+            Object[] args) {
+            super(sessionKey, exclusiveSessionLockWaitTime);
+            this.deploymentInfo = deploymentInfo;
+            this.primKey = primKey;
+            this.callMethod = callMethod;
+            this.callInterface = callInterface;
+            this.args = args;
+        }
+
+        public Object getResult() {
+            return result;
+        }
+
+        @Override
+        protected void doInvoke() throws InvocationException {
+            invokeEJBMethod();
+        }
+        
+        @Override
+        protected void doInvoke(InvocationContext context) throws InvocationException {
+            invokeEJBMethod();
+        }
+
+        protected abstract void invokeEJBMethod() throws InvocationException;
+    }
+    
+    protected class BusinessMethodInvocation extends AbstractEJBInvocation {
+        
+        protected BusinessMethodInvocation(String sessionKey,
+            long exclusiveSessionLockWaitTime,
+            CoreDeploymentInfo deploymentInfo,
+            Object primKey,
+            Class callInterface,
+            Method callMethod,
+            Object[] args) {
+            super(sessionKey, exclusiveSessionLockWaitTime, deploymentInfo, primKey, callInterface, callMethod, args);
+        }
+    
+        protected void invokeEJBMethod() throws InvocationException {
+            try {
+                result = superBusinessMethod(deploymentInfo, primKey, callInterface, callMethod, args);
+            } catch (OpenEJBException e) {
+                throw new InvocationException(e);
+            }
+        }
+    }
+    
+    protected class RemoveEJBObjectInvocation extends AbstractEJBInvocation {
+
+        protected RemoveEJBObjectInvocation(String sessionKey,
+            long exclusiveSessionLockWaitTime,
+            CoreDeploymentInfo deploymentInfo,
+            Object primKey,
+            Class callInterface,
+            Method callMethod,
+            Object[] args) {
+            super(sessionKey, exclusiveSessionLockWaitTime, deploymentInfo, primKey, callInterface, callMethod, args);
+        }
+        
+        protected void invokeEJBMethod() throws InvocationException {
+            try {
+                result = superRemoveEJBObject(deploymentInfo, primKey, callInterface, callMethod, args);
+            } catch (OpenEJBException e) {
+                throw new InvocationException(e);
+            }
+        }
+        
+    }
+
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulInstanceManager.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulInstanceManager.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulInstanceManager.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/container/ClusteredStatefulInstanceManager.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,231 @@
+/*
+ * 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.openejb.cluster.stateful.container;
+
+import java.lang.reflect.Method;
+import java.rmi.dgc.VMID;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.clustering.Session;
+import org.apache.geronimo.clustering.SessionAlreadyExistException;
+import org.apache.geronimo.clustering.SessionListener;
+import org.apache.geronimo.clustering.SessionManager;
+import org.apache.geronimo.openejb.cluster.infra.SessionManagerTracker;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.SystemException;
+import org.apache.openejb.core.CoreDeploymentInfo;
+import org.apache.openejb.core.ThreadContext;
+import org.apache.openejb.core.stateful.BeanEntry;
+import org.apache.openejb.core.stateful.StatefulInstanceManager;
+import org.apache.openejb.core.stateful.StatefulContainer.MethodType;
+import org.apache.openejb.persistence.JtaEntityManagerRegistry;
+import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Index;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class ClusteredStatefulInstanceManager extends StatefulInstanceManager implements SessionManagerTracker {
+    private final Map<Object, SessionManager> sessionManagersById;
+    private final Map<Object, CoreDeploymentInfo> deploymentsById;
+
+    public ClusteredStatefulInstanceManager(TransactionManager transactionManager,
+        SecurityService securityService,
+        JtaEntityManagerRegistry jtaEntityManagerRegistry,
+        Class passivatorClass,
+        int timeout,
+        int poolSize,
+        int bulkPassivate) throws OpenEJBException {
+        super(transactionManager,
+            securityService,
+            jtaEntityManagerRegistry,
+            passivatorClass,
+            timeout,
+            poolSize,
+            bulkPassivate);
+        
+        sessionManagersById = new HashMap<Object, SessionManager>();
+        deploymentsById = new HashMap<Object, CoreDeploymentInfo>();
+    }
+    
+    public void addSessionManager(Object deploymentId, SessionManager sessionManager) {
+        synchronized (sessionManagersById) {
+            sessionManagersById.put(deploymentId, sessionManager);
+        }
+        sessionManager.registerListener(new MigrationListener());
+    }
+    
+    public void removeSessionManager(Object deploymentId, SessionManager sessionManager) {
+        synchronized (sessionManagersById) {
+            sessionManagersById.remove(deploymentId);
+        }
+    }
+    
+    @Override
+    public void deploy(CoreDeploymentInfo deploymentInfo, Index<Method, MethodType> index) throws OpenEJBException {
+        synchronized (deploymentsById) {
+            deploymentsById.put(deploymentInfo.getDeploymentID(), deploymentInfo);
+        }
+        super.deploy(deploymentInfo, index);
+    }
+    
+    @Override
+    public void undeploy(CoreDeploymentInfo deploymentInfo) throws OpenEJBException {
+        synchronized (deploymentsById) {
+            deploymentsById.remove(deploymentInfo.getDeploymentID());
+        }
+        super.undeploy(deploymentInfo);
+    }
+    
+    @Override
+    protected BeanEntry newBeanEntry(Object primaryKey, Object bean) {
+        ThreadContext threadContext = ThreadContext.getThreadContext();
+        if (null == threadContext) {
+            throw new IllegalStateException("No ThreadContext");
+        }
+        Object deploymentId = threadContext.getDeploymentInfo().getDeploymentID();
+
+        SessionManager sessionManager;
+        synchronized (sessionManagersById) {
+            sessionManager = sessionManagersById.get(deploymentId);
+        }
+        if (null == sessionManager) {
+            throw new IllegalStateException("No SessionManager registered for deployment [" + deploymentId + "]");
+        }
+        
+        Session session;
+        try {
+            if (!(primaryKey instanceof VMID)) {
+                // primaryKey.toString() must be an unique String representation for an unique identifier. Here, we
+                // check that primaryKey is a VMID as its Object.toString implementation returns an unique String
+                // representation. Other types may not implement Object.toString() "correctly".
+                throw new AssertionError("primaryKey MUST be a " + VMID.class.getName());
+            }
+            session = sessionManager.createSession(primaryKey.toString());
+        } catch (SessionAlreadyExistException e) {
+            throw (IllegalStateException) new IllegalStateException().initCause(e);
+        }
+        
+        return new ClusteredBeanEntry(session, deploymentId, bean, primaryKey, timeOut);
+    }
+
+    @Override
+    protected void onFreeBeanEntry(ThreadContext callContext, BeanEntry entry) {
+        SessionOperation operation = callContext.get(SessionOperation.class);
+        if (null != operation) {
+            if (SessionOperation.DESTRUCTION != operation && SessionOperation.OUTBOUND_MIGRATION != operation) {
+                throw new AssertionError();
+            }
+            return;
+        }
+        ClusteredBeanEntry clusteredBeanEntry = (ClusteredBeanEntry) entry;
+        clusteredBeanEntry.release();
+    }
+    
+    @Override
+    protected void onPoolInstanceWithoutTransaction(ThreadContext callContext, BeanEntry entry) {
+        SessionOperation operation = callContext.get(SessionOperation.class);
+        if (null != operation) {
+            if (SessionOperation.INBOUND_MIGRATION != operation) {
+                throw new AssertionError();
+            }
+            return;
+        }
+        ClusteredBeanEntry clusteredBeanEntry = (ClusteredBeanEntry) entry;
+        clusteredBeanEntry.endAccess();
+    }
+    
+    protected enum SessionOperation {
+        INBOUND_MIGRATION,
+        OUTBOUND_MIGRATION,
+        DESTRUCTION
+    }
+    
+    protected class MigrationListener implements SessionListener {
+        private final Log log = LogFactory.getLog(MigrationListener.class);
+
+        public void notifyInboundSessionMigration(org.apache.geronimo.clustering.Session session) {
+            ClusteredBeanEntry beanEntry = new ClusteredBeanEntry(session);
+            ThreadContext context = newThreadContext(beanEntry);
+            if (null == context) {
+                return;
+            }
+            context.set(SessionOperation.class, SessionOperation.INBOUND_MIGRATION);
+
+            try {
+                activateInstance(context, beanEntry);
+                poolInstance(context, beanEntry.getBean());
+            } catch (Exception e) {
+                log.warn("Cannot activate migrated bean entry.", e);
+            }
+        }
+
+        public void notifyOutboundSessionMigration(org.apache.geronimo.clustering.Session session) {
+            ClusteredBeanEntry beanEntry = new ClusteredBeanEntry(session);
+            ThreadContext context = newThreadContext(beanEntry);
+            if (null == context) {
+                return;
+            }
+            context.set(SessionOperation.class, SessionOperation.OUTBOUND_MIGRATION);
+
+            passivate(context, beanEntry);
+            try {
+                freeInstance(context);
+            } catch (SystemException e) {
+                log.warn("Cannot free bean entry", e);
+            }
+        }
+
+        public void notifySessionDestruction(org.apache.geronimo.clustering.Session session) {
+            ClusteredBeanEntry beanEntry = new ClusteredBeanEntry(session);
+            ThreadContext context = newThreadContext(beanEntry);
+            if (null == context) {
+                return;
+            }
+            context.set(SessionOperation.class, SessionOperation.DESTRUCTION);
+            
+            try {
+                freeInstance(context);
+            } catch (SystemException e) {
+                log.warn("Cannot free bean entry", e);
+            }
+        }
+
+        protected ThreadContext newThreadContext(ClusteredBeanEntry beanEntry) {
+            Object deploymentId = beanEntry.getDeploymentId();
+            CoreDeploymentInfo deploymentInfo;
+            synchronized (deploymentsById) {
+                deploymentInfo = deploymentsById.get(deploymentId);
+            }
+            if (null == deploymentInfo) {
+                log.warn("Deployment [" + deploymentId + "] is unknown.");
+                return null;
+            }
+            return new ThreadContext(deploymentInfo, beanEntry.getPrimaryKey());
+        }
+    }
+    
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/deployment/ClusteredStatefulDeployment.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/deployment/ClusteredStatefulDeployment.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/deployment/ClusteredStatefulDeployment.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/java/org/apache/geronimo/openejb/cluster/stateful/deployment/ClusteredStatefulDeployment.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,236 @@
+/*
+ * 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.openejb.cluster.stateful.deployment;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.security.auth.login.LoginException;
+
+import org.apache.geronimo.clustering.SessionManager;
+import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
+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.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.naming.enc.EnterpriseNamingContext;
+import org.apache.geronimo.openejb.EjbDeployment;
+import org.apache.geronimo.openejb.EjbDeploymentGBean;
+import org.apache.geronimo.openejb.OpenEjbSystem;
+import org.apache.geronimo.openejb.cluster.infra.SessionManagerTracker;
+import org.apache.geronimo.security.jacc.RunAsSource;
+import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
+import org.apache.openejb.Container;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class ClusteredStatefulDeployment extends EjbDeployment implements GBeanLifecycle {
+
+    private final SessionManager sessionManager;
+
+    public ClusteredStatefulDeployment() throws LoginException {
+        sessionManager = null;
+    }
+
+    public ClusteredStatefulDeployment(String objectName,
+        String deploymentId,
+        String ejbName,
+        String homeInterfaceName,
+        String remoteInterfaceName,
+        String localHomeInterfaceName,
+        String localInterfaceName,
+        String serviceEndpointInterfaceName,
+        String beanClassName,
+        ClassLoader classLoader,
+        boolean securityEnabled,
+        String defaultRole,
+        String runAsRole,
+        RunAsSource runAsSource,
+        Map componentContext,
+        Set unshareableResources,
+        Set applicationManagedSecurityResources,
+        TrackedConnectionAssociator trackedConnectionAssociator,
+        GeronimoTransactionManager transactionManager,
+        OpenEjbSystem openEjbSystem,
+        SessionManager sessionManager,
+        Kernel kernel) throws Exception {
+        this(objectName,
+            deploymentId,
+            ejbName,
+            homeInterfaceName,
+            remoteInterfaceName,
+            localHomeInterfaceName,
+            localInterfaceName,
+            serviceEndpointInterfaceName,
+            beanClassName,
+            classLoader,
+            securityEnabled,
+            defaultRole,
+            runAsRole,
+            runAsSource,
+            EnterpriseNamingContext.createEnterpriseNamingContext(componentContext,
+                transactionManager,
+                kernel,
+                classLoader),
+            unshareableResources,
+            applicationManagedSecurityResources,
+            trackedConnectionAssociator,
+            openEjbSystem,
+            sessionManager);
+    }
+    
+    public ClusteredStatefulDeployment(String objectName,
+        String deploymentId,
+        String ejbName,
+        String homeInterfaceName,
+        String remoteInterfaceName,
+        String localHomeInterfaceName,
+        String localInterfaceName,
+        String serviceEndpointInterfaceName,
+        String beanClassName,
+        ClassLoader classLoader,
+        boolean securityEnabled,
+        String defaultRole,
+        String runAsRole,
+        RunAsSource runAsSource,
+        Context componentContext,
+        Set unshareableResources,
+        Set applicationManagedSecurityResources,
+        TrackedConnectionAssociator trackedConnectionAssociator,
+        OpenEjbSystem openEjbSystem,
+        SessionManager sessionManager) throws LoginException {
+        super(objectName,
+            deploymentId,
+            ejbName,
+            homeInterfaceName,
+            remoteInterfaceName,
+            localHomeInterfaceName,
+            localInterfaceName,
+            serviceEndpointInterfaceName,
+            beanClassName,
+            classLoader,
+            securityEnabled,
+            defaultRole,
+            runAsRole,
+            runAsSource,
+            componentContext,
+            unshareableResources,
+            applicationManagedSecurityResources,
+            trackedConnectionAssociator,
+            openEjbSystem);
+        if (null == sessionManager) {
+            throw new IllegalArgumentException("sessionManager is required");
+        }
+        this.sessionManager = sessionManager;
+    }
+
+    public void doStart() throws Exception {
+        start();
+    }
+
+    public void doStop() throws Exception {
+        stop();
+    }
+
+    public void doFail() {
+        stop();
+    }
+
+    protected void start() throws Exception {
+        super.start();
+
+        Container container = deploymentInfo.getContainer();
+        if (null == container) {
+            throw new IllegalStateException("Container not assigned to deployment " + deploymentId);
+        }
+        if (!(container instanceof SessionManagerTracker)) {
+            throw new IllegalStateException("Container for deployment [" + deploymentId + "] is not a ["
+                    + SessionManagerTracker.class.getName() + "]. It is a [" + container.getClass().getName() + "]");
+        }
+        SessionManagerTracker sessionManagerTracker = (SessionManagerTracker) container;
+        sessionManagerTracker.addSessionManager(deploymentId, sessionManager);
+    }
+
+    protected void stop() {
+        if (null != deploymentInfo) {
+            Container container = deploymentInfo.getContainer();
+            if (null != container) {
+                SessionManagerTracker sessionManagerTracker = (SessionManagerTracker) container;
+                sessionManagerTracker.removeSessionManager(deploymentId, sessionManager);
+            }
+        }
+
+        super.stop();
+    }
+
+    public static final GBeanInfo GBEAN_INFO;
+
+    public static final String GBEAN_REF_SESSION_MANAGER = "SessionManager";
+
+    static {
+        GBeanInfoBuilder builder = GBeanInfoBuilder.createStatic(ClusteredStatefulDeployment.class,
+            ClusteredStatefulDeployment.class,
+            EjbDeploymentGBean.GBEAN_INFO,
+            NameFactory.STATEFUL_SESSION_BEAN);
+        
+        builder.addReference(GBEAN_REF_SESSION_MANAGER, SessionManager.class, NameFactory.GERONIMO_SERVICE);
+        
+        builder.setConstructor(new String[] { "objectName",
+            "deploymentId",
+            "ejbName",
+
+            "homeInterfaceName",
+            "remoteInterfaceName",
+            "localHomeInterfaceName",
+            "localInterfaceName",
+            "serviceEndpointInterfaceName",
+            "beanClassName",
+            "classLoader",
+
+            "securityEnabled",
+            "defaultRole",
+            "runAsRole",
+            "RunAsSource",
+
+            "componentContextMap",
+
+            "unshareableResources",
+            "applicationManagedSecurityResources",
+            "TrackedConnectionAssociator",
+            "TransactionManager",
+
+            "OpenEjbSystem",
+            GBEAN_REF_SESSION_MANAGER,
+
+            "kernel"
+        });
+        
+        GBEAN_INFO = builder.getBeanInfo();
+    }
+
+    public static GBeanInfo getGBeanInfo() {
+        return GBEAN_INFO;
+    }
+
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/resources/META-INF/org.apache.geronimo.openejb.cluster/service-jar.xml
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/resources/META-INF/org.apache.geronimo.openejb.cluster/service-jar.xml?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/resources/META-INF/org.apache.geronimo.openejb.cluster/service-jar.xml (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/main/resources/META-INF/org.apache.geronimo.openejb.cluster/service-jar.xml Fri Feb 22 17:02:57 2008
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+-->
+
+<!-- $Rev: 610927 $ $Date: 2008-01-11 07:48:37 +1100 (Fri, 11 Jan 2008) $ -->
+
+<ServiceJar>
+
+  <!--
+  # ==========================================================
+  # Default Clustered Stateful Container
+  # ==========================================================
+  -->
+  <ServiceProvider
+          id="Default Clustered Stateful Container"
+          service="Container"
+          types="STATEFUL"
+          constructor="id, transactionManager, securityService, Passivator, TimeOut, PoolSize, BulkPassivate"
+          class-name="org.apache.geronimo.openejb.cluster.stateful.container.ClusteredStatefulContainer">
+
+    # The passivator is responsible for writing beans to disk
+    # at passivation time. Different passivators can be used
+    # by setting this property to the fully qualified class name
+    # of the PassivationStrategy implementation. The passivator
+    # is not responsible for invoking any callbacks or other
+    # processing, its only responsibly is to write the bean state
+    # to disk.
+    #
+    # Known implementations:
+    # org.apache.openejb.core.stateful.RAFPassivater
+    # org.apache.openejb.core.stateful.SimplePassivater
+
+    Passivator org.apache.openejb.core.stateful.SimplePassivater
+
+    # Specifies the time to wait between invocations. This
+    # value is measured in minutes. A value of 5 would
+    # result in a time-out of 5 minutes between invocations.
+    # A value of zero would mean no timeout.
+
+    TimeOut 20
+
+    # Specifies the size of the bean pools for this
+    # stateful SessionBean container.
+
+    PoolSize 1000
+
+    # Property name that specifies the number of instances
+    # to passivate at one time when doing bulk passivation.
+
+    BulkPassivate 100
+
+  </ServiceProvider>
+
+</ServiceJar>

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerTest.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerTest.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/BasicNetworkConnectorTrackerTest.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,103 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ * @version $Rev:$ $Date:$
+ */
+public class BasicNetworkConnectorTrackerTest extends TestCase {
+
+    public void testRegistration() throws Exception {
+        BasicNetworkConnectorTracker tracker = new BasicNetworkConnectorTracker();
+        String deploymentId = "deploymentId";
+
+        URI uri1 = new URI("uri1");
+        tracker.registerNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri1));
+        Set<URI> connectorURIs = tracker.getConnectorURIs(deploymentId);
+        assertEquals(1, connectorURIs.size());
+        assertTrue(connectorURIs.contains(uri1));
+        
+        URI uri2 = new URI("uri2");
+        tracker.registerNetworkConnectorLocations(deploymentId, "nodeName2", Collections.singleton(uri2));
+        connectorURIs = tracker.getConnectorURIs(deploymentId);
+        assertEquals(2, connectorURIs.size());
+        assertTrue(connectorURIs.contains(uri1));
+        assertTrue(connectorURIs.contains(uri2));
+    }
+    
+    public void testUnregistration() throws Exception {
+        BasicNetworkConnectorTracker tracker = new BasicNetworkConnectorTracker();
+        String deploymentId = "deploymentId";
+
+        URI uri1 = new URI("uri1");
+        URI uri2 = new URI("uri2");
+        tracker.registerNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri1));
+        tracker.registerNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri2));
+        tracker.unregisterNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri2));
+        Set<URI> connectorURIs = tracker.getConnectorURIs(deploymentId);
+        assertEquals(1, connectorURIs.size());
+        assertTrue(connectorURIs.contains(uri1));
+    }
+    
+    public void testUnregistrationForAllURIs() throws Exception {
+        BasicNetworkConnectorTracker tracker = new BasicNetworkConnectorTracker();
+        String deploymentId = "deploymentId";
+        
+        URI uri1 = new URI("uri1");
+        tracker.registerNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri1));
+        tracker.unregisterNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri1));
+        try {
+            tracker.getConnectorURIs(deploymentId);
+            fail();
+        } catch (NetworkConnectorTrackerException e) {
+        }
+    }
+    
+    public void testUnregistrationForNode() throws Exception {
+        BasicNetworkConnectorTracker tracker = new BasicNetworkConnectorTracker();
+        String deploymentId = "deploymentId";
+        
+        URI uri1 = new URI("uri1");
+        tracker.registerNetworkConnectorLocations(deploymentId, "nodeName", Collections.singleton(uri1));
+        tracker.unregisterNetworkConnectorLocations("nodeName");
+        try {
+            tracker.getConnectorURIs(deploymentId);
+            fail();
+        } catch (NetworkConnectorTrackerException e) {
+        }
+    }
+    
+    public void testGetConnectorURIsThrowsNCEWhenNoURIsForDeploymentId() throws Exception {
+        BasicNetworkConnectorTracker tracker = new BasicNetworkConnectorTracker();
+        try {
+            tracker.getConnectorURIs("deploymentId");
+            fail();
+        } catch (NetworkConnectorTrackerException e) {
+        }
+    }
+    
+}

Added: geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitorTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitorTest.java?rev=630370&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitorTest.java (added)
+++ geronimo/server/trunk/plugins/openejb/geronimo-openejb-clustering-wadi/src/test/java/org/apache/geronimo/openejb/cluster/infra/NetworkConnectorMonitorTest.java Fri Feb 22 17:02:57 2008
@@ -0,0 +1,327 @@
+/*
+ * 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.openejb.cluster.infra;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Set;
+
+import org.apache.geronimo.clustering.Node;
+import org.apache.geronimo.clustering.SessionManagerListener;
+import org.apache.geronimo.clustering.wadi.NodeService;
+import org.apache.geronimo.clustering.wadi.RemoteNode;
+import org.apache.geronimo.clustering.wadi.WADISessionManager;
+import org.apache.geronimo.gbean.ReferenceCollection;
+import org.apache.geronimo.gbean.ReferenceCollectionEvent;
+import org.apache.geronimo.gbean.ReferenceCollectionListener;
+import org.apache.geronimo.management.geronimo.NetworkConnector;
+import org.apache.geronimo.openejb.EjbDeploymentIdAccessor;
+import org.codehaus.wadi.group.Peer;
+import org.codehaus.wadi.servicespace.InvocationMetaData;
+import org.codehaus.wadi.servicespace.ServiceProxy;
+import org.codehaus.wadi.servicespace.ServiceProxyFactory;
+
+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 NetworkConnectorMonitorTest extends RMockTestCase {
+
+    private NetworkConnectorMonitor monitor;
+    private ReferenceCollection connectors;
+    private ReferenceCollectionListener connectorListener;
+    private ReferenceCollection deployments;
+    private ReferenceCollectionListener deploymentListener;
+    private WADISessionManager manager;
+    private SessionManagerListener managerListener;
+    private ServiceProxyFactory trackerProxyFactory;
+    private NetworkConnectorTrackerProxy tracker;
+    private Collection<EjbDeploymentIdAccessor> mockStartingDeployments;
+    private Collection<NetworkConnector> mockStartingConnectors;
+    private String nodeName;
+    private NetworkConnectorTracker localTracker;
+
+    @Override
+    protected void setUp() throws Exception {
+        connectors = (ReferenceCollection) mock(ReferenceCollection.class, "connectors");
+        connectors.addReferenceCollectionListener(null);
+        modify().args(new AbstractExpression() {
+            public void describeWith(ExpressionDescriber arg0) throws IOException {
+            }
+            public boolean passes(Object arg0) {
+                connectorListener = (ReferenceCollectionListener) arg0;
+                return true;
+            }
+        });
+        
+        deployments = (ReferenceCollection) mock(ReferenceCollection.class, "deployments");
+        deployments.addReferenceCollectionListener(null);
+        modify().args(new AbstractExpression() {
+            public void describeWith(ExpressionDescriber arg0) throws IOException {
+            }
+            public boolean passes(Object arg0) {
+                deploymentListener = (ReferenceCollectionListener) arg0;
+                return true;
+            }
+        });
+        
+        manager = (WADISessionManager) mock(WADISessionManager.class);
+        manager.registerSessionManagerListener(null);
+        modify().args(new AbstractExpression() {
+            public void describeWith(ExpressionDescriber arg0) throws IOException {
+            }
+
+            public boolean passes(Object arg0) {
+                managerListener = (SessionManagerListener) arg0;
+                return true;
+            }
+        });
+        
+        manager.getCluster().getLocalNode().getName();
+        nodeName = "nodeName";
+        modify().returnValue(nodeName);
+        
+        trackerProxyFactory = (ServiceProxyFactory) mock(ServiceProxyFactory.class);
+        
+        tracker = (NetworkConnectorTrackerProxy) mock(NetworkConnectorTrackerProxy.class);
+        trackerProxyFactory.getProxy();
+        modify().returnValue(tracker);
+    }
+    
+    public void testDeploymentLocationsAreRegisteredUponStart() throws Exception {
+        recordStart();
+        
+        startVerificationAndDoStartMonitor();
+    }
+
+    public void testAddConnectorEventTriggersTrackerRegistration() throws Exception {
+        new ExecuteConnectorEventTest() {
+            @Override
+            protected void executeListenerCallback(ReferenceCollectionEvent event) {
+                connectorListener.memberAdded(event);
+            }
+            @Override
+            protected void executeTrackerOperation(String deploymentId, Set<URI> locations) {
+                tracker.registerNetworkConnectorLocations(deploymentId, nodeName, locations);
+            }
+        }.executeTest();
+    }
+
+    public void testRemoveConnectorEventTriggersTrackerUnregistration() throws Exception {
+        new ExecuteConnectorEventTest() {
+            @Override
+            protected void executeListenerCallback(ReferenceCollectionEvent event) {
+                connectorListener.memberRemoved(event);
+            }
+            @Override
+            protected void executeTrackerOperation(String deploymentId, Set<URI> locations) {
+                tracker.unregisterNetworkConnectorLocations(deploymentId, nodeName, locations);
+            }
+        }.executeTest();
+    }
+    
+    public void testAddDeploymentEventTriggersTrackerRegistration() throws Exception {
+        new ExecuteDeploymentEventTest() {
+            @Override
+            protected void executeListenerCallback(ReferenceCollectionEvent event) {
+                deploymentListener.memberAdded(event);
+            }
+            @Override
+            protected void executeTrackerOperation(String deploymentId, Set<URI> locations) {
+                tracker.registerNetworkConnectorLocations(deploymentId, nodeName, locations);
+            }
+        }.executeTest();
+    }
+    
+    public void testRemoveDeploymentEventTriggersTrackerUnregistration() throws Exception {
+        new ExecuteDeploymentEventTest() {
+            @Override
+            protected void executeListenerCallback(ReferenceCollectionEvent event) {
+                deploymentListener.memberRemoved(event);
+            }
+            @Override
+            protected void executeTrackerOperation(String deploymentId, Set<URI> locations) {
+                tracker.unregisterNetworkConnectorLocations(deploymentId, nodeName, locations);
+            }
+        }.executeTest();
+    }
+
+    public void testJoiningNodeTriggersTrackerRegistrationForJoiningNode() throws Exception {
+        recordStart();
+        
+        deployments.iterator();
+        modify().returnValue(mockStartingDeployments.iterator());
+
+        Peer joiningPeer = (Peer) mock(Peer.class);
+        joiningPeer.getLocalStateMap();
+        modify().returnValue(new HashMap());
+        joiningPeer.getName();
+        modify().returnValue("joiningPeer");
+        
+        NodeService nodeService = (NodeService) mock(NodeService.class);
+
+        NetworkConnectorTrackerProxy proxy = (NetworkConnectorTrackerProxy) mock(NetworkConnectorTrackerProxy.class,
+            "NetworkConnectorTrackerProxy2");
+        trackerProxyFactory.getProxy();
+        modify().returnValue(proxy);
+        
+        InvocationMetaData invocationMetaData = (InvocationMetaData) mock(InvocationMetaData.class);
+        proxy.getInvocationMetaData();
+        modify().returnValue(invocationMetaData);
+        invocationMetaData.setTargets(new Peer[] {joiningPeer});
+        
+        proxy.registerNetworkConnectorLocations("deploymentId", nodeName, Collections.singleton(new URI("ejbd://host:1")));
+        
+        startVerificationAndDoStartMonitor();
+        
+        RemoteNode joiningNode = new RemoteNode(joiningPeer, nodeService);
+        
+        managerListener.onJoin(joiningNode, null);
+    }
+
+    public void testLeavingNodeTriggersLocalTrackerUnRegistration() throws Exception {
+        recordStart();
+        
+        Node leavingNode = (Node) mock(Node.class);
+        leavingNode.getName();
+        String leavingNodeName = "leavingNode";
+        modify().returnValue(leavingNodeName);
+
+        localTracker.unregisterNetworkConnectorLocations(leavingNodeName);
+        
+        startVerificationAndDoStartMonitor();
+
+        managerListener.onLeave(leavingNode, null);
+    }
+    
+    protected void startVerificationAndDoStartMonitor() throws Exception {
+        startVerification();
+        
+        monitor = newMonitor();
+        monitor.doStart();
+    }
+    
+    protected abstract class ExecuteDeploymentEventTest {
+        public void executeTest() throws Exception {
+            recordStart();
+
+            String deploymentId2 = "deploymentId2";
+            EjbDeploymentIdAccessor idAccessor2 = newDeploymentIdAccessor(deploymentId2);
+
+            trackerProxyFactory.getProxy();
+            modify().returnValue(tracker);
+            executeTrackerOperation(deploymentId2, Collections.singleton(new URI("ejbd://host:1")));
+
+            startVerificationAndDoStartMonitor();
+            
+            ReferenceCollectionEvent event = new ReferenceCollectionEvent("name", idAccessor2);
+            executeListenerCallback(event);
+        }
+        
+        protected abstract void executeTrackerOperation(String deploymentId, Set<URI> locations);
+        
+        protected abstract void executeListenerCallback(ReferenceCollectionEvent event);
+    }
+    
+    protected abstract class ExecuteConnectorEventTest {
+        public void executeTest() throws Exception {
+            recordStart();
+
+            deployments.iterator();
+            modify().returnValue(mockStartingDeployments.iterator());
+
+            NetworkConnector connector = newConnector(2);
+
+            trackerProxyFactory.getProxy();
+            modify().returnValue(tracker);
+            executeTrackerOperation("deploymentId", Collections.singleton(new URI("ejbd://host:2")));
+
+            startVerificationAndDoStartMonitor();
+            
+            ReferenceCollectionEvent event = new ReferenceCollectionEvent("name", connector);
+            executeListenerCallback(event);
+        }
+        
+        protected abstract void executeTrackerOperation(String deploymentId, Set<URI> locations);
+        
+        protected abstract void executeListenerCallback(ReferenceCollectionEvent event);
+    }
+    
+    private NetworkConnectorMonitor newMonitor() {
+        return new NetworkConnectorMonitor(connectors, deployments, manager) {
+            @Override
+            protected ServiceProxyFactory newNetworkConnectorTrackerProxy() {
+                return trackerProxyFactory;
+            }
+        };
+    }
+
+    protected void recordStart() throws Exception {
+        localTracker = (NetworkConnectorTracker) mock(NetworkConnectorTracker.class);
+        manager.getServiceSpace().getServiceRegistry().getStartedService(NetworkConnectorTracker.NAME);
+        modify().returnValue(localTracker);
+        
+        mockStartingDeployments = new ArrayList<EjbDeploymentIdAccessor>();
+        String deploymentId = "deploymentId";
+        EjbDeploymentIdAccessor idAccessor = newDeploymentIdAccessor(deploymentId);
+        mockStartingDeployments.add(idAccessor);
+        deployments.iterator();
+        modify().returnValue(mockStartingDeployments.iterator());
+
+        mockStartingConnectors = new ArrayList<NetworkConnector>();
+        NetworkConnector connector = newConnector(1);
+        mockStartingConnectors.add(connector);
+        connectors.iterator();
+        modify().returnValue(mockStartingConnectors.iterator());
+        
+        tracker.registerNetworkConnectorLocations(deploymentId, nodeName, Collections.singleton(new URI("ejbd://host:1")));
+    }
+
+    private EjbDeploymentIdAccessor newDeploymentIdAccessor(String deploymentId) {
+        EjbDeploymentIdAccessor idAccessor = (EjbDeploymentIdAccessor) mock(EjbDeploymentIdAccessor.class,
+            "EjbDeploymentIdAccessor" + deploymentId);
+        idAccessor.getDeploymentId();
+        modify().multiplicity(expect.from(0)).returnValue(deploymentId);
+        return idAccessor;
+    }
+
+    private NetworkConnector newConnector(int port) {
+        NetworkConnector connector = (NetworkConnector) mock(NetworkConnector.class, "NetworkConnector" + port);
+        connector.getHost();
+        modify().returnValue("host");
+        connector.getPort();
+        modify().returnValue(port);
+        connector.getProtocol();
+        modify().returnValue("ejbd");
+        return connector;
+    }
+
+    public interface NetworkConnectorTrackerProxy extends NetworkConnectorTracker, ServiceProxy {
+    }
+
+}