You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2012/03/23 07:19:27 UTC

svn commit: r1304199 [1/2] - in /openejb/branches/openejb-3.1.x/server: openejb-client/ openejb-client/src/main/java/org/apache/openejb/client/ openejb-client/src/main/java/org/apache/openejb/client/event/ openejb-client/src/main/resources/ openejb-cli...

Author: dblevins
Date: Fri Mar 23 06:19:26 2012
New Revision: 1304199

URL: http://svn.apache.org/viewvc?rev=1304199&view=rev
Log:
Porting from trunk:

OPENEJB-1801	Improved StickyConnectionStrategy for clustering and failover
OPENEJB-1802	Improved RoundRobinConnectionStrategy for clustering and failover
OPENEJB-1803	Improved RandomConnectionStrategy for clustering and failover
OPENEJB-1804	Client Event API for monitoring connection, clustering and failover activity
OPENEJB-1805	All client logging revised and greatly expanded
OPENEJB-1806	New "sticky+random" ConnectionStrategy
OPENEJB-1807	New "sticky+round" ConnectionStrategy
OPENEJB-1808	Client property 'openejb.client.connection.strategy' can be set as System or InitialContext property
OPENEJB-1809	RandomConnectionStrategy fixed reliability issues
OPENEJB-1810	Client Event issued when Servers Added/Removed from cluster
OPENEJB-1811	Client Event issued on connection Failover and Request Retry
OPENEJB-1812	Client Event issued on Configuration change


Added:
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/AbstractConnectionStrategy.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java
      - copied, changed from r1302856, openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Context.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/EventLogger.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Observers.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/BootstrappingConnection.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClientVersion.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClusterMetaDataUpdated.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryAdded.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryRemoved.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFailed.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionOpened.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionStrategyAdded.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionStrategyFailed.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionStrategyRemoved.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/FailoverSelection.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/Log.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ObserverAdded.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ObserverRemoved.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/Observes.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RandomFailoverSelection.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RemoteInitialContextCreated.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RequestFailed.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RetryConditionAdded.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RetryConditionRemoved.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RetryingRequest.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/RoundRobinFailoverSelection.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ServerAdded.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ServerRemoved.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/StickyFailoverSelection.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/resources/openejb-client-version.properties
Removed:
    openejb/branches/openejb-3.1.x/server/openejb-client/src/test/java/org/apache/openejb/client/StickyConnectionStrategyTest.java
Modified:
    openejb/branches/openejb-3.1.x/server/openejb-client/pom.xml
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClusterMetaData.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ConnectionManager.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RandomConnectionStrategy.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RoundRobinConnectionStrategy.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/SocketConnectionFactory.java
    openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/StickyConnectionStrategy.java
    openejb/branches/openejb-3.1.x/server/openejb-ejbd/src/test/java/org/apache/openejb/server/ejbd/FullPoolFailoverTest.java

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/pom.xml
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/pom.xml?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/pom.xml (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/pom.xml Fri Mar 23 06:19:26 2012
@@ -36,6 +36,12 @@
     </openejb.osgi.import.pkg>
   </properties>
   <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -64,6 +70,29 @@
           </excludes>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <tstamp>
+                  <format property="TSTAMP" pattern="hh:mm"/>
+                </tstamp>
+                <replace file="target/classes/openejb-client-version.properties"
+                         token="@DATE-REPLACED-BY-MAVEN@" value="${DSTAMP}"/>
+                <replace file="target/classes/openejb-client-version.properties"
+                         token="@TIME-REPLACED-BY-MAVEN@" value="${TSTAMP}"/>
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <dependencies>

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/AbstractConnectionStrategy.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/AbstractConnectionStrategy.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/AbstractConnectionStrategy.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/AbstractConnectionStrategy.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,105 @@
+/*
+ * 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.openejb.client;
+
+import org.apache.openejb.client.event.BootstrappingConnection;
+import org.apache.openejb.client.event.FailoverSelection;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public abstract class AbstractConnectionStrategy implements ConnectionStrategy {
+    public Connection connect(ClusterMetaData cluster, ServerMetaData server) throws IOException {
+        final Set<URI> failed = Client.getFailed();
+        final Set<URI> remaining = new HashSet<URI>();
+
+        boolean failover = false;
+
+        final Iterable<URI> iterable = getIterable(cluster);
+        for (URI uri : iterable) {
+            if (failed.contains(uri)) continue;
+
+            if (failover) Client.fireEvent(createFailureEvent(remaining, failed, uri));
+
+            try {
+                return connect(cluster, uri);
+            } catch (IOException e) {
+
+                if (!failover) {
+                    Collections.addAll(remaining, cluster.getLocations());
+                    remaining.removeAll(failed);
+                }
+
+                failed.add(uri);
+                remaining.remove(uri);
+                failover = true;
+            }
+        }
+
+        final URI uri = server.getLocation();
+
+        if (uri == null) throw new RemoteFailoverException("Attempted to connect to " + failed.size() + " servers.");
+
+        Client.fireEvent(new BootstrappingConnection(uri));
+
+        return connect(cluster, uri);
+    }
+
+    private Iterable<URI> getIterable(ClusterMetaData cluster) {
+        final Context context = cluster.getContext();
+        final StrategyData data = context.getComponent(StrategyData.class);
+
+        if (data != null) return data.getIterable();
+
+        context.setComponent(StrategyData.class, new StrategyData(createIterable(cluster)));
+
+        return getIterable(cluster);
+    }
+
+    protected abstract FailoverSelection createFailureEvent(Set<URI> remaining, Set<URI> failed, URI uri);
+
+    protected abstract Iterable<URI> createIterable(ClusterMetaData cluster);
+
+    protected Connection connect(ClusterMetaData cluster, URI uri) throws IOException {
+        Connection connection = ConnectionManager.getConnection(uri);
+
+        // Grabbing the URI from the associated connection allows the ConnectionFactory to
+        // employ discovery to find and connect to a server.  We then attempt to connect
+        // to the discovered server rather than repeat the discovery process again.
+        cluster.setLastLocation(connection.getURI());
+        return connection;
+    }
+
+    private static class StrategyData {
+        private final Iterable<URI> iterable;
+
+        private StrategyData(Iterable<URI> iterable) {
+            this.iterable = iterable;
+        }
+
+        public Iterable<URI> getIterable() {
+            return iterable;
+        }
+    }
+}

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java Fri Mar 23 06:19:26 2012
@@ -16,6 +16,8 @@
  */
 package org.apache.openejb.client;
 
+import org.apache.openejb.client.event.*;
+
 import static org.apache.openejb.client.Exceptions.newIOException;
 
 import java.io.EOFException;
@@ -26,7 +28,9 @@ import java.io.ObjectOutput;
 import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.rmi.RemoteException;
+import java.util.Arrays;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.List;
@@ -37,10 +41,10 @@ import java.util.logging.Logger;
 import java.net.URI;
 
 public class Client {
-    private static final Logger logger = Logger.getLogger("OpenEJB.client");
-    private static final boolean FINEST = logger.isLoggable(Level.FINEST);
-    private static final boolean FINER = logger.isLoggable(Level.FINER);
-    private static final boolean FINE = logger.isLoggable(Level.FINE);
+    private static final Logger logger = Logger.getLogger(Client.class.getName());
+    private boolean FINEST = logger.isLoggable(Level.FINEST);
+    private boolean FINER = logger.isLoggable(Level.FINER);
+    private boolean FINE = logger.isLoggable(Level.FINE);
 
     public static final ThreadLocal<Set<URI>> failed = new ThreadLocal<Set<URI>>();
 
@@ -50,21 +54,53 @@ public class Client {
     private static Client client = new Client();
     private boolean retry = false;
 
+    private final Observers observers = new Observers();
+
     public Client() {
         String retryValue = System.getProperty("openejb.client.requestretry", getRetry() + "");
         retry = Boolean.valueOf(retryValue);
+
+        observers.addObserver(new EventLogger());
+        observers.fireEvent(new ClientVersion());
+    }
+
+    public static void addEventObserver(Object observer) {
+        if (observer == null) throw new IllegalArgumentException("observer cannot be null");
+
+        if (client.observers.addObserver(observer)) {
+            fireEvent(new ObserverAdded(observer));
+        }
+    }
+
+    public static void removeEventObserver(Object observer) {
+        if (observer == null) throw new IllegalArgumentException("observer cannot be null");
+
+        if (client.observers.removeObserver(observer)) {
+            fireEvent(new ObserverAdded(observer));
+        }
+    }
+
+    public static void fireEvent(Object event) {
+        client.observers.fireEvent(event);
     }
 
     public static boolean addRetryCondition(Class<? extends Throwable> throwable) {
-        return client.retryConditions.add(throwable);
+        if (throwable == null) throw new IllegalArgumentException("throwable cannot be null");
+        final boolean add = client.retryConditions.add(throwable);
+        if (add) fireEvent(new RetryConditionAdded(throwable));
+        return add;
     }
 
     public static boolean removeRetryCondition(Class<? extends Throwable> throwable) {
-        return client.retryConditions.remove(throwable);
+        if (throwable == null) throw new IllegalArgumentException("throwable cannot be null");
+        final boolean remove = client.retryConditions.remove(throwable);
+        if (remove) fireEvent(new RetryConditionRemoved(throwable));
+        return remove;
     }
 
     // This lame hook point if only of testing
     public static void setClient(Client client) {
+        if (client == null) throw new IllegalArgumentException("client cannot be null");
         Client.client = client;
     }
 
@@ -290,13 +326,19 @@ public class Client {
             final URI uri = conn.getURI();
             final Set<URI> failed = getFailed();
 
+            Client.fireEvent(new RequestFailed(uri, req));
+
             if (FINER) {
                 logger.log(Level.FINER, "Add Failed " + uri.toString());
             }
             failed.add(uri);
             conn.discard();
-            if (e instanceof RetryException || getRetry()){
+
+            if (e instanceof RetryException || getRetry()) {
                 try {
+
+                    Client.fireEvent(new RetryingRequest(req, server));
+
                     processRequest(req, res, server);
                 } catch (RemoteFailoverException re) {
                     throw re;
@@ -349,36 +391,99 @@ public class Client {
         return set;
     }
 
-    private static final Map<ServerMetaData, ClusterMetaData> clusters = new ConcurrentHashMap<ServerMetaData, ClusterMetaData>();
-
     private static void setClusterMetaData(ServerMetaData server, ClusterMetaData cluster) {
+        final Context context = getContext(server);
+        context.setClusterMetaData(cluster);
+    }
+
+    private static ClusterMetaData getClusterMetaData(ServerMetaData server) {
+        return getContext(server).getClusterMetaData();
+    }
+
+    //openejb.client.connection.strategy
+
+    private boolean getRetry() {
+        return retry = Boolean.valueOf(System.getProperty("openejb.client.requestretry", retry + ""));
+    }
+
+    private static final Map<ServerMetaData, Context> contexts = new ConcurrentHashMap<ServerMetaData, Context>();
 
-        if (FINE) {
-            logger.log(Level.FINE, "Update ClusterMetaData(version=" + cluster.getVersion() + ", uris=" + cluster.getLocations().length);
+    public static Context getContext(ServerMetaData serverMetaData) {
+        Context context = contexts.get(serverMetaData);
+        if (context == null) {
+            context = new Context(serverMetaData);
+            contexts.put(serverMetaData, context);
         }
+        return context;
+    }
+
+    public static class Context {
+        private final Properties properties = new Properties();
+        private final ServerMetaData serverMetaData;
+        private ClusterMetaData clusterMetaData;
+        private Options options;
+
+        private Context(ServerMetaData serverMetaData) {
+            this.serverMetaData = serverMetaData;
+            this.clusterMetaData = new ClusterMetaData(0, serverMetaData.getLocation());
+
+            options = new Options(properties, new Options(System.getProperties()));
+        }
+
+        public ServerMetaData getServerMetaData() {
+            return serverMetaData;
+        }
+
+        public ClusterMetaData getClusterMetaData() {
+            return clusterMetaData;
+        }
+
+        public void setClusterMetaData(ClusterMetaData updated) {
+            if (updated == null) throw new IllegalArgumentException("clusterMetaData cannot be null");
+
+            ClusterMetaData previous = this.clusterMetaData;
+            this.clusterMetaData = updated;
+
+            if (updated.getConnectionStrategy() == null) {
+                updated.setConnectionStrategy(previous.getConnectionStrategy());
+            }
+            updated.setLastLocation(previous.getLastLocation());
+            final ClusterMetaDataUpdated clusterMetaDataUpdated = new ClusterMetaDataUpdated(serverMetaData, updated, clusterMetaData);
+
+            fireEvent(clusterMetaDataUpdated);
+
+            final Set<URI> found = locations(updated);
+            final Set<URI> existing = locations(previous);
 
-        if (FINER) {
-            int i = 0;
-            for (URI uri : cluster.getLocations()) {
-                final String format = String.format("ClusterMetaData(version=%s) - URI #%s %s", cluster.getVersion(), ++i, uri.toASCIIString());
-                logger.log(Level.FINER, format);
+            for (URI uri : diff(existing, found)) {
+                fireEvent(new ServerAdded(clusterMetaDataUpdated, uri));
             }
+
+            for (URI uri : diff(found, existing)) {
+                fireEvent(new ServerRemoved(clusterMetaDataUpdated, uri));
+            }
+
         }
 
-        clusters.put(server, cluster);
-    }
+        private HashSet<URI> locations(ClusterMetaData updated) {
+            return new HashSet<URI>(Arrays.asList(updated.getLocations()));
+        }
 
-    private static ClusterMetaData getClusterMetaData(ServerMetaData server) {
-        ClusterMetaData cluster = clusters.get(server);
-        if (cluster == null) {
-            cluster = new ClusterMetaData(0, server.getLocation());
-            clusters.put(server, cluster);
+        public Properties getProperties() {
+            return properties;
         }
 
-        return cluster;
-    }
+        public Options getOptions() {
+            return options;
+        }
 
-    private boolean getRetry() {
-        return retry = Boolean.valueOf(System.getProperty("openejb.client.requestretry", retry + ""));
+        public Set<URI> diff(Set<URI> a, Set<URI> b) {
+            final Set<URI> diffs = new HashSet<URI>();
+            for (URI uri : b) {
+                if (!a.contains(uri)) diffs.add(uri);
+            }
+
+            return diffs;
+        }
     }
 }

Copied: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java (from r1302856, openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java)
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java?p2=openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java&p1=openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java&r1=1302856&r2=1304199&rev=1304199&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClientRuntimeException.java Fri Mar 23 06:19:26 2012
@@ -1,3 +1,19 @@
+/**
+ * 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.openejb.client;
 
 public class ClientRuntimeException extends RuntimeException {

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClusterMetaData.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClusterMetaData.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClusterMetaData.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ClusterMetaData.java Fri Mar 23 06:19:26 2012
@@ -30,7 +30,8 @@ public class ClusterMetaData implements 
     private URI[] locations;
     private long version;
     private String connectionStrategy;
-    private URI lastLocation;
+    private volatile URI lastLocation;
+    private transient final Context context = new Context();
 
     public ClusterMetaData() {
     }
@@ -40,6 +41,10 @@ public class ClusterMetaData implements 
         this.version = version;
     }
 
+    public Context getContext() {
+        return context;
+    }
+
     public URI getLastLocation() {
         return lastLocation;
     }

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ConnectionManager.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ConnectionManager.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ConnectionManager.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/ConnectionManager.java Fri Mar 23 06:19:26 2012
@@ -16,6 +16,13 @@
  */
 package org.apache.openejb.client;
 
+import org.apache.openejb.client.event.ConnectionFactoryAdded;
+import org.apache.openejb.client.event.ConnectionFactoryRemoved;
+import org.apache.openejb.client.event.ConnectionFailed;
+import org.apache.openejb.client.event.ConnectionStrategyAdded;
+import org.apache.openejb.client.event.ConnectionStrategyFailed;
+import org.apache.openejb.client.event.Log;
+
 import java.io.IOException;
 import java.net.URI;
 import java.util.Properties;
@@ -31,26 +38,31 @@ public class ConnectionManager {
     static {
         SocketConnectionFactory ejbdFactory = new SocketConnectionFactory();
 
-        factories.register("default", ejbdFactory);
-        factories.register("ejbd", ejbdFactory);
-        factories.register("ejbds", ejbdFactory);
+        registerFactory("default", ejbdFactory);
+        registerFactory("ejbd", ejbdFactory);
+        registerFactory("ejbds", ejbdFactory);
 
         HttpConnectionFactory httpFactory = new HttpConnectionFactory();
-        factories.register("http", httpFactory);
-        factories.register("https", httpFactory);
+        registerFactory("http", httpFactory);
+        registerFactory("https", httpFactory);
 
-        factories.register("multicast", new MulticastConnectionFactory());
-        factories.register("failover", new FailoverConnectionFactory());
+        registerFactory("multicast", new MulticastConnectionFactory());
+        registerFactory("failover", new FailoverConnectionFactory());
         
-        strategies.register("sticky", new StickyConnectionStrategy());
-        strategies.register("random", new RandomConnectionStrategy());
-        strategies.register("roundrobin", new RoundRobinConnectionStrategy());
-        strategies.register("round-robin", strategies.get("roundrobin"));
-        strategies.register("default", strategies.get("sticky"));
+        registerStrategy("sticky", new StickyConnectionStrategy());
+        registerStrategy("sticky+random", new StickyConnectionStrategy(new RandomConnectionStrategy()));
+        registerStrategy("sticky+round", new StickyConnectionStrategy(new RoundRobinConnectionStrategy()));
+        registerStrategy("random", new RandomConnectionStrategy());
+        registerStrategy("roundrobin", new RoundRobinConnectionStrategy());
+        registerStrategy("round-robin", strategies.get("roundrobin"));
+        registerStrategy("default", strategies.get("sticky"));
     }
 
 
     public static Connection getConnection(ClusterMetaData cluster, ServerMetaData server, Request req) throws IOException {
+        if (cluster == null) throw new IllegalArgumentException("cluster cannot be null");
+        if (server == null) throw new IllegalArgumentException("server cannot be null");
+
         String name = cluster.getConnectionStrategy();
 
         if (req instanceof EJBRequest) {
@@ -58,41 +70,73 @@ public class ConnectionManager {
             final Properties p = ejbRequest.getEjbMetaData().getProperties();
             name = p.getProperty("openejb.client.connection.strategy", name);
         }
+
         if (name == null) name = "default";
 
         ConnectionStrategy strategy = strategies.get(name);
 
-        if (strategy == null) throw new IOException("Unsupported ConnectionStrategy  \"" + name + "\"");
+        try {
+            if (strategy == null) throw new UnsupportedConnectionStrategyException(name);
 
-        logger.fine("connect: strategy=" + name + ", uri=" + server.getLocation() + ", strategy-impl=" + strategy.getClass().getName());
-        return strategy.connect(cluster, server);
+            // On finest because this happens every invocation
+            logger.finest("connect: strategy=" + name + ", uri=" + server.getLocation() + ", strategy-impl=" + strategy.getClass().getName());
+
+            return strategy.connect(cluster, server);
+        } catch (IOException e) {
+            Client.fireEvent(new ConnectionStrategyFailed(strategy, cluster, server, e));
+            throw e;
+        }
     }
 
     public static Connection getConnection(URI uri) throws IOException {
+        if (uri == null) throw new IllegalArgumentException("uri cannot be null");
         String scheme = uri.getScheme();
 
         ConnectionFactory factory = factories.get(scheme);
 
-        if (factory == null) throw new IOException("Unsupported ConnectionFactory URI scheme  \"" + scheme + "\"");
-
-        logger.fine("connect: scheme=" + scheme + ", uri=" + uri + ", factory-impl=" + factory.getClass().getName());
-        return factory.getConnection(uri);
+        try {
+            if (factory == null) {
+                throw new UnsupportedConnectionFactoryException(scheme);
+            }
+
+            // On finest because this happens every invocation
+            logger.finest("connect: scheme=" + scheme + ", uri=" + uri + ", factory-impl=" + factory.getClass().getName());
+
+            return factory.getConnection(uri);
+        } catch (IOException e) {
+            Client.fireEvent(new ConnectionFailed(uri, e));
+            throw e;
+        }
     }
 
     public static void registerFactory(String scheme, ConnectionFactory factory) {
         factories.register(scheme, factory);
+        Client.fireEvent(new ConnectionFactoryAdded(scheme, factory));
     }
 
     public static ConnectionFactory unregisterFactory(String scheme) {
-        return factories.unregister(scheme);
+        final ConnectionFactory factory = factories.unregister(scheme);
+
+        if (factory != null){
+            Client.fireEvent(new ConnectionFactoryRemoved(scheme, factory));
+        }
+
+        return factory;
     }
 
     public static void registerStrategy(String scheme, ConnectionStrategy factory) {
         strategies.register(scheme, factory);
+        Client.fireEvent(new ConnectionStrategyAdded(scheme, factory));
     }
 
     public static ConnectionStrategy unregisterStrategy(String scheme) {
-        return strategies.unregister(scheme);
+        final ConnectionStrategy strategy = strategies.unregister(scheme);
+
+        if (strategy != null) {
+            Client.fireEvent(new ConnectionStrategyAdded(scheme, strategy));
+        }
+
+        return strategy;
     }
 
     /**
@@ -103,4 +147,18 @@ public class ConnectionManager {
     public static void setFactory(ConnectionFactory factory) throws IOException {
         registerFactory("default", factory);
     }
+
+    @Log(Log.Level.SEVERE)
+    public static class UnsupportedConnectionStrategyException extends IOException {
+        public UnsupportedConnectionStrategyException(String message) {
+            super(message);
+        }
+    }
+
+    @Log(Log.Level.SEVERE)
+    public static class UnsupportedConnectionFactoryException extends IOException {
+        public UnsupportedConnectionFactoryException(String message) {
+            super(message);
+        }
+    }
 }

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Context.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Context.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Context.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Context.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,42 @@
+/*
+ * 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.openejb.client;
+
+import java.util.HashMap;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class Context {
+
+    private final HashMap<Class, Object> components = new HashMap<Class, Object>();
+
+    @SuppressWarnings({"unchecked"})
+    public <T> T getComponent(Class<T> type) {
+        return (T) components.get(type);
+    }
+
+    @SuppressWarnings({"unchecked"})
+    public <T> T setComponent(Class<T> type, T component) {
+        return (T) components.put(type, component);
+    }
+
+    @SuppressWarnings({"unchecked"})
+    public <T> T removeComponent(Class<T> type) {
+        return (T) components.remove(type);
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/EventLogger.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/EventLogger.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/EventLogger.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/EventLogger.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,70 @@
+/*
+ * 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.openejb.client;
+
+import org.apache.openejb.client.event.ClusterMetaDataUpdated;
+import org.apache.openejb.client.event.Log;
+import org.apache.openejb.client.event.Observes;
+
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class EventLogger {
+
+    public void log(@Observes ClusterMetaDataUpdated event) {
+        final Logger logger = Logger.getLogger(event.getClass().getName());
+
+        final ClusterMetaData cluster = event.getClusterMetaData();
+
+        final String msg = event.toString();
+
+        if (logger.isLoggable(Level.FINE)) {
+            logger.log(Level.FINE, msg);
+        }
+
+        if (logger.isLoggable(Level.FINER)) {
+            int i = 0;
+            for (URI uri : cluster.getLocations()) {
+                final String format = String.format("%s #%s %s", msg, ++i, uri.toASCIIString());
+                logger.log(Level.FINER, format);
+            }
+        }
+    }
+
+    public void log(@Observes Object event) {
+        final Log log = event.getClass().getAnnotation(Log.class);
+
+        if (log == null) return;
+
+        final Logger logger = Logger.getLogger(event.getClass().getName());
+
+        try {
+            final Level level = Level.parse(log.value().name());
+
+            if (logger.isLoggable(level)) {
+                logger.log(level, event.toString());
+            }
+
+        } catch (IllegalArgumentException e) {
+            logger.log(Level.WARNING, event.toString());
+        }
+    }
+}

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java Fri Mar 23 06:19:26 2012
@@ -16,33 +16,36 @@
  */
 package org.apache.openejb.client;
 
+import org.apache.openejb.client.event.RemoteInitialContextCreated;
 import org.omg.CORBA.ORB;
 
-import java.io.Serializable;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.ConnectException;
-import java.rmi.RemoteException;
-import java.util.Hashtable;
-import java.util.Properties;
-import java.util.ArrayList;
-import java.util.List;
-import java.lang.reflect.Constructor;
 import javax.naming.AuthenticationException;
+import javax.naming.Binding;
+import javax.naming.CompoundName;
 import javax.naming.ConfigurationException;
 import javax.naming.Context;
 import javax.naming.InvalidNameException;
 import javax.naming.Name;
+import javax.naming.NameClassPair;
 import javax.naming.NameNotFoundException;
 import javax.naming.NameParser;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
 import javax.naming.ServiceUnavailableException;
-import javax.naming.NameClassPair;
-import javax.naming.Binding;
 import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.NamingManager;
 import javax.sql.DataSource;
+import java.lang.reflect.Constructor;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
 
 /** 
  * @version $Rev$ $Date$
@@ -100,7 +103,7 @@ public class JNDIContext implements Init
         String providerUrl = (String) env.get(Context.PROVIDER_URL);
         moduleId = (String) env.get("openejb.client.moduleId");
 
-        URI location;
+        final URI location;
         try {
             providerUrl = addMissingParts(providerUrl);
             location = new URI(providerUrl);
@@ -108,6 +111,15 @@ public class JNDIContext implements Init
             throw (ConfigurationException) new ConfigurationException("Property value for " + Context.PROVIDER_URL + " invalid: " + providerUrl + " - " + e.getMessage()).initCause(e);
         }
         this.server = new ServerMetaData(location);
+
+        final Client.Context context = Client.getContext(this.server);
+        context.getProperties().putAll(environment);
+
+        final String strategy = context.getOptions().get("openejb.client.connection.strategy", "default");
+        context.getClusterMetaData().setConnectionStrategy(strategy);
+
+        Client.fireEvent(new RemoteInitialContextCreated(location));
+
         //TODO:1: Either aggressively initiate authentication or wait for the
         //        server to send us an authentication challange.
         if (userID != null) {
@@ -274,7 +286,7 @@ public class JNDIContext implements Init
                 throw (Error) res.getResult();
 
             default:
-                throw new RuntimeException("Invalid response from server: " + res.getResponseCode());
+                throw new ClientRuntimeException("Invalid response from server: " + res.getResponseCode());
         }
     }
 
@@ -381,7 +393,7 @@ public class JNDIContext implements Init
                 throw (Error) res.getResult();
 
             default:
-                throw new RuntimeException("Invalid response from server :" + res.getResponseCode());
+                throw new ClientRuntimeException("Invalid response from server :" + res.getResponseCode());
         }
 
     }
@@ -426,7 +438,7 @@ public class JNDIContext implements Init
                 try {
                     super.setObject(context.lookup(getName()));
                 } catch (NamingException e) {
-                    throw failed = new RuntimeException("Failed to lazily fetch the binding '"+getName()+"'", e);
+                    throw failed = new ClientRuntimeException("Failed to lazily fetch the binding '"+getName()+"'", e);
                 }
             }
             return super.getObject();
@@ -446,11 +458,11 @@ public class JNDIContext implements Init
     }
 
     public NameParser getNameParser(String name) throws NamingException {
-        throw new OperationNotSupportedException("TODO: Needs to be implemented");
+        return new SimpleNameParser();
     }
 
     public NameParser getNameParser(Name name) throws NamingException {
-        return getNameParser(name.toString());
+        return new SimpleNameParser();
     }
 
     public String composeName(String name, String prefix) throws NamingException {
@@ -528,5 +540,23 @@ public class JNDIContext implements Init
         return createSubcontext(name.toString());
     }
 
+    private static final class SimpleNameParser implements NameParser {
+         private static final Properties PARSER_PROPERTIES = new Properties();
+
+         static {
+             PARSER_PROPERTIES.put("jndi.syntax.direction", "left_to_right");
+             PARSER_PROPERTIES.put("jndi.syntax.separator", "/");
+         }
+
+
+         private SimpleNameParser() {
+         }
+
+         public Name parse(String name) throws NamingException {
+             return new CompoundName(name, PARSER_PROPERTIES);
+         }
+     }
+
+
 }
 

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Observers.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Observers.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Observers.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/Observers.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,164 @@
+/*
+ * 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.openejb.client;
+
+import org.apache.openejb.client.event.Observes;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class Observers {
+    private static final Logger logger = Logger.getLogger("OpenEJB.client");
+
+    private final List<Observer> observers = new ArrayList<Observer>();
+
+    public boolean addObserver(Object observer) {
+        if (observer == null) throw new IllegalArgumentException("observer cannot be null");
+        return observers.add(new Observer(observer));
+    }
+
+    public boolean removeObserver(Object listener) {
+        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+        return observers.remove(new Observer(listener));
+    }
+
+    public void fireEvent(Object event) {
+        if (event == null) throw new IllegalArgumentException("event cannot be null");
+
+        for (Observer observer : observers) {
+            try {
+                observer.invoke(event);
+            } catch (InvocationTargetException e) {
+                final Throwable t = e.getTargetException() == null ? e : e.getTargetException();
+
+                if (e.getTargetException() != null) {
+                    logger.log(Level.WARNING, "Observer method invocation failed", t);
+                }
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * @version $Rev$ $Date$
+     */
+    public static class Observer {
+        private final Map<Class, Method> methods = new HashMap<Class, Method>();
+        private final Object observer;
+        private final Method defaultMethod;
+
+        public Observer(Object observer) {
+            if (observer == null) throw new IllegalArgumentException("observer cannot be null");
+
+            this.observer = observer;
+            for (Method method : observer.getClass().getMethods()) {
+                if (!isObserver(method)) continue;
+
+                if (method.getParameterTypes().length > 1) {
+                    throw new IllegalArgumentException("@Observes method must have only 1 parameter: " + method.toString());
+                }
+
+                if (Modifier.isAbstract(method.getModifiers())) {
+                    throw new IllegalArgumentException("@Observes method must not be abstract: " + method.toString());
+                }
+
+                if (!Modifier.isPublic(method.getModifiers())) {
+                    throw new IllegalArgumentException("@Observes method must be public: " + method.toString());
+                }
+
+                final Class<?> type = method.getParameterTypes()[0];
+
+                if (type.isAnnotation()) {
+                    throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an annotation): " + method.toString());
+                }
+
+                if (Modifier.isAbstract(type.getModifiers())) {
+                    throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an abstract class): " + method.toString());
+                }
+
+                if (type.isInterface()) {
+                    throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an interface): " + method.toString());
+                }
+
+                if (type.isArray()) {
+                    throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an array): " + method.toString());
+                }
+
+                if (type.isPrimitive()) {
+                    throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not a primitive): " + method.toString());
+                }
+
+                methods.put(type, method);
+            }
+
+            defaultMethod = methods.get(Object.class);
+
+            if (methods.size() == 0) {
+                throw new IllegalArgumentException("Object has no @Observes methods. For example: public void observe(@Observes RetryConditionAdded event){...}");
+            }
+        }
+
+        public void invoke(Object event) throws InvocationTargetException, IllegalAccessException {
+            if (event == null) throw new IllegalArgumentException("event cannot be null");
+
+            final Class eventType = event.getClass();
+            final Method method = methods.get(eventType);
+
+            if (method != null) {
+                method.invoke(observer, event);
+            } else if (defaultMethod != null) {
+                defaultMethod.invoke(observer, event);
+            }
+        }
+
+        private boolean isObserver(Method method) {
+            for (Annotation[] annotations : method.getParameterAnnotations()) {
+                for (Annotation annotation : annotations) {
+                    if (annotation.annotationType().equals(Observes.class)) return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            final Observer observer1 = (Observer) o;
+
+            return observer.equals(observer1.observer);
+        }
+
+        @Override
+        public int hashCode() {
+            return observer.hashCode();
+        }
+    }
+}

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RandomConnectionStrategy.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RandomConnectionStrategy.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RandomConnectionStrategy.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RandomConnectionStrategy.java Fri Mar 23 06:19:26 2012
@@ -16,83 +16,77 @@
  */
 package org.apache.openejb.client;
 
-import java.io.IOException;
+import org.apache.openejb.client.event.FailoverSelection;
+import org.apache.openejb.client.event.RandomFailoverSelection;
+
 import java.net.URI;
-import java.rmi.RemoteException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.Set;
 import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.List;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 import java.util.Random;
+import java.util.Set;
 
-public class RandomConnectionStrategy implements ConnectionStrategy {
-    private static final Logger LOGGER = Logger.getLogger("OpenEJB.client");
-    private final Random random = new Random();
+public class RandomConnectionStrategy extends AbstractConnectionStrategy {
 
+    @Override
+    protected FailoverSelection createFailureEvent(Set<URI> remaining, Set<URI> failed, URI uri) {
+        return new RandomFailoverSelection(remaining, failed, uri);
+    }
 
-    public Connection connect(ClusterMetaData cluster, ServerMetaData server) throws IOException {
-        Set<URI> failed = Client.getFailed();
+    @Override
+    protected Iterable<URI> createIterable(ClusterMetaData cluster) {
+        return new RandomIterable(cluster);
+    }
 
-        URI[] locations = cluster.getLocations();
+    public static class RandomIterable implements Iterable<URI> {
+        private final URI[] locations;
 
-        if (locations.length == 0){
-            return connect(cluster, server.getLocation());
+        public RandomIterable(ClusterMetaData clusterMetaData) {
+            this.locations = clusterMetaData.getLocations();
         }
 
-        List<URI> available = Arrays.asList(locations);
-        available.removeAll(failed);
-
-        URI lastLocation = cluster.getLastLocation();
-
-        if (available.size() > 2) available.remove(lastLocation);
-
-
-        while (available.size() > 0) {
-
-            URI uri = next(available);
-
-            try {
-                return connect(cluster, uri);
-            } catch (IOException e) {
-                failed.add(uri);
-                available.remove(uri);
-                LOGGER.log(Level.WARNING, "Random: Failover: Cannot connect to server(s): " + uri.toString() + " Exception: " + e.getMessage()+".  Trying next.");
-            } catch (Throwable e) {
-                failed.add(uri);
-                available.remove(uri);
-                throw new RemoteException("Random: Failover: Cannot connect to server: " +  uri.toString() + " due to an unkown exception in the OpenEJB client: ", e);
-            }
+        @Override
+        public Iterator<URI> iterator() {
+            return new RandomIterator<URI>(locations);
         }
+    }
 
-        if (available.size() == 0 && server.getLocation() != null && !failed.contains(server.getLocation())){
-            return connect(cluster, server.getLocation());
+    public static class RandomIterator<T> implements Iterator<T> {
+        private final Random random = new Random();
+        private final T[] items;
+        private int size;
+
+        public RandomIterator(T[] items) {
+            this.items = Arrays.copyOf(items, items.length);
+            this.size = items.length;
         }
 
-        // If no servers responded, throw an error
-        StringBuilder buffer = new StringBuilder();
-        for (int i = 0; i < locations.length; i++) {
-            URI uri = locations[i];
-            buffer.append((i != 0 ? ", " : "") + "Server #" + i + ": " + uri);
+        @Override
+        public boolean hasNext() {
+            return size > 0;
         }
-        throw new RemoteException("Cannot connect to any servers: " + buffer.toString());
-    }
 
-    private URI next(List<URI> available) {
-        int i = Math.abs(random.nextInt()) % available.size();
-        URI uri = available.get(i);
-        return uri;
-    }
+        @Override
+        public T next() {
+            if (!hasNext()) throw new NoSuchElementException();
+
+            // Random.nextInt is exclusive.
+            // So if size=10, result will be between 0-9
+            final int selected = random.nextInt(size--);
+
+            T selectedObject = items[selected];
+
+            // Take the object from the end of the list
+            // and move it into the place where selected was.
+            items[selected] = items[size];
+            items[size] = null;
 
-    protected Connection connect(ClusterMetaData cluster, URI uri) throws IOException {
-        Connection connection = ConnectionManager.getConnection(uri);
+            return selectedObject;
+        }
 
-        // Grabbing the URI from the associated connection allows the ConnectionFactory to
-        // employ discovery to find and connect to a server.  We then attempt to connect
-        // to the discovered server rather than repeat the discovery process again.
-        cluster.setLastLocation(connection.getURI());
-        return connection;
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException("remove");
+        }
     }
-
 }
\ No newline at end of file

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RoundRobinConnectionStrategy.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RoundRobinConnectionStrategy.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RoundRobinConnectionStrategy.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/RoundRobinConnectionStrategy.java Fri Mar 23 06:19:26 2012
@@ -16,87 +16,71 @@
  */
 package org.apache.openejb.client;
 
-import java.io.IOException;
+import org.apache.openejb.client.event.FailoverSelection;
+import org.apache.openejb.client.event.RoundRobinFailoverSelection;
+
 import java.net.URI;
-import java.rmi.RemoteException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 import java.util.Set;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.List;
-
-public class RoundRobinConnectionStrategy implements ConnectionStrategy {
-    private static final Logger LOGGER = Logger.getLogger("OpenEJB.client");
+import java.util.concurrent.atomic.AtomicInteger;
 
-    public Connection connect(ClusterMetaData cluster, ServerMetaData server) throws IOException {
-        Set<URI> failed = Client.getFailed();
+public class RoundRobinConnectionStrategy extends AbstractConnectionStrategy {
 
-        URI[] locations = cluster.getLocations();
+    private static class RoundRobinIterable implements Iterable<URI> {
+        private final URI[] locations;
+        private AtomicInteger index = new AtomicInteger(-1);
 
-        if (locations.length == 0){
-            return connect(cluster, server.getLocation());
+        private RoundRobinIterable(ClusterMetaData clusterMetaData) {
+            this.locations = clusterMetaData.getLocations();
         }
 
+        private int index() {
+            final int i = index.incrementAndGet();
+            if (i < locations.length) return i;
 
-        List<URI> list = Arrays.asList(locations);
-        URI lastLocation = cluster.getLastLocation();
-        if (null != lastLocation && !failed.contains(lastLocation)) {
-            try {
-                int i = list.indexOf(lastLocation) + 1;
-                if (i >= list.size()) i = 0;
-
-                URI uri = list.get(i);
-
-                return connect(cluster, uri);
-            } catch (IOException e) {
-                if (locations.length > 1){
-                    LOGGER.log(Level.WARNING, "RoundRobin: Failing over.  Cannot connect to next server: " + lastLocation.toString() + " Exception: " + e.getClass().getName() +" " + e.getMessage());
-                }
-            }
+            index.compareAndSet(i, -1);
+            return index();
         }
 
+        @Override
+        public Iterator<URI> iterator() {
+            return new RoundRobinIterator();
+        }
 
-        Set<URI> remaining = new LinkedHashSet<URI>(list);
-
-        remaining.remove(lastLocation);
-        remaining.removeAll(failed);
+        private class RoundRobinIterator implements Iterator<URI> {
+            private final Set<URI> seen = new HashSet<URI>();
 
-        for (URI uri : remaining) {
-            try {
-                return connect(cluster, uri);
-            } catch (IOException e) {
-                failed.add(uri);
-                LOGGER.log(Level.WARNING, "RoundRobin: Failover: Cannot connect to server(s): " + uri.toString() + " Exception: " + e.getMessage()+".  Trying next.");
-            } catch (Throwable e) {
-                failed.add(uri);
-                throw new RemoteException("RoundRobin: Failover: Cannot connect to server: " +  uri.toString() + " due to an unkown exception in the OpenEJB client: ", e);
+            @Override
+            public boolean hasNext() {
+                return seen.size() < locations.length;
             }
-        }
 
-        remaining.removeAll(failed);
+            @Override
+            public URI next() {
+                if (!hasNext()) throw new NoSuchElementException();
 
-        if (remaining.size() == 0 && server.getLocation() != null && !failed.contains(server.getLocation())){
-            return connect(cluster, server.getLocation());
-        }
+                final URI location = locations[index()];
+                seen.add(location);
+
+                return location;
+            }
 
-        // If no servers responded, throw an error
-        StringBuilder buffer = new StringBuilder();
-        for (int i = 0; i < locations.length; i++) {
-            URI uri = locations[i];
-            buffer.append((i != 0 ? ", " : "") + "Server #" + i + ": " + uri);
+            @Override
+            public void remove() {
+            }
         }
-        throw new RemoteException("Cannot connect to any servers: " + buffer.toString());
     }
 
-    protected Connection connect(ClusterMetaData cluster, URI uri) throws IOException {
-        Connection connection = ConnectionManager.getConnection(uri);
+    @Override
+    protected FailoverSelection createFailureEvent(Set<URI> remaining, Set<URI> failed, URI uri) {
+        return new RoundRobinFailoverSelection(remaining, failed, uri);
+    }
 
-        // Grabbing the URI from the associated connection allows the ConnectionFactory to
-        // employ discovery to find and connect to a server.  We then attempt to connect
-        // to the discovered server rather than repeat the discovery process again.
-        cluster.setLastLocation(connection.getURI());
-        return connection;
+    @Override
+    protected Iterable<URI> createIterable(ClusterMetaData cluster) {
+        return new RoundRobinIterable(cluster);
     }
 
 }
\ No newline at end of file

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/SocketConnectionFactory.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/SocketConnectionFactory.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/SocketConnectionFactory.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/SocketConnectionFactory.java Fri Mar 23 06:19:26 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.openejb.client;
 
+import org.apache.openejb.client.event.*;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import java.io.BufferedInputStream;
@@ -190,6 +191,7 @@ public class SocketConnectionFactory imp
                 }
 
                 socket.setTcpNoDelay(true);
+                Client.fireEvent(new ConnectionOpened(uri));
             } catch (ConnectException e) {
                 throw new ConnectException("Cannot connect to server '" + uri.toString() + "'.  Check that the server is started and that the specified serverURL is correct.");
 

Modified: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/StickyConnectionStrategy.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/StickyConnectionStrategy.java?rev=1304199&r1=1304198&r2=1304199&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/StickyConnectionStrategy.java (original)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/StickyConnectionStrategy.java Fri Mar 23 06:19:26 2012
@@ -16,78 +16,100 @@
  */
 package org.apache.openejb.client;
 
-import java.io.IOException;
+import org.apache.openejb.client.event.FailoverSelection;
+import org.apache.openejb.client.event.StickyFailoverSelection;
+
 import java.net.URI;
-import java.rmi.RemoteException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 import java.util.Set;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
 
-public class StickyConnectionStrategy implements ConnectionStrategy {
-    private static final Logger LOGGER = Logger.getLogger("OpenEJB.client");
+public class StickyConnectionStrategy extends AbstractConnectionStrategy {
+
+
+    private final AbstractConnectionStrategy secondaryConnectionStrategy;
+
+    public StickyConnectionStrategy() {
+        this(new RoundRobinConnectionStrategy());
+    }
+
+    public StickyConnectionStrategy(AbstractConnectionStrategy secondaryConnectionStrategy) {
+        this.secondaryConnectionStrategy = secondaryConnectionStrategy;
+    }
+
+    public AbstractConnectionStrategy getSecondaryConnectionStrategy() {
+        return secondaryConnectionStrategy;
+    }
+
+    @Override
+    protected FailoverSelection createFailureEvent(Set<URI> remaining, Set<URI> failed, URI uri) {
+        return new StickyFailoverSelection(remaining, failed, uri);
+    }
+
+    @Override
+    protected Iterable<URI> createIterable(ClusterMetaData cluster) {
+        return new StickyIterable(cluster);
+    }
 
-    public Connection connect(ClusterMetaData cluster, ServerMetaData server) throws IOException {
-        Set<URI> failed = Client.getFailed();
+    public class StickyIterable implements Iterable<URI> {
 
-        URI[] locations = cluster.getLocations();
+        private final ClusterMetaData cluster;
+        private final Iterable<URI> iterable;
 
-        if (locations.length == 0){
-            return connect(cluster, server.getLocation());
+        public StickyIterable(ClusterMetaData cluster) {
+            this.cluster = cluster;
+            this.iterable = secondaryConnectionStrategy.createIterable(cluster);
         }
 
-        URI lastLocation = cluster.getLastLocation();
-        if (null != lastLocation && !failed.contains(lastLocation)) {
-            try {
-                return connect(cluster, lastLocation);
-            } catch (IOException e) {
-                if (locations.length > 1){
-                    LOGGER.log(Level.WARNING, "Failing over.  Cannot connect to last server: " + lastLocation.toString() + " Exception: " + e.getClass().getName() +" " + e.getMessage());
-                }
-            }
+        @Override
+        public Iterator<URI> iterator() {
+            return new StickyIterator();
         }
 
+        public class StickyIterator implements Iterator<URI> {
+            private Iterator<URI> iterator;
+            private URI last;
+            private boolean first = true;
 
-        Set<URI> remaining = new LinkedHashSet<URI>(Arrays.asList(locations));
-        remaining.remove(lastLocation);
-        remaining.removeAll(failed);
-
-        for (URI uri : remaining) {
-            try {
-                return connect(cluster, uri);
-            } catch (IOException e) {
-                failed.add(uri);
-                LOGGER.log(Level.WARNING, "Failover: Cannot connect to server(s): " + uri.toString() + " Exception: " + e.getMessage()+".  Trying next.");
-            } catch (Throwable e) {
-                failed.add(uri);
-                throw new RemoteException("Failover: Cannot connect to server: " +  uri.toString() + " due to an unkown exception in the OpenEJB client: ", e);
+            private StickyIterator() {
+                setLast(cluster.getLastLocation());
             }
-        }
 
-        remaining.removeAll(failed);
+            private void setLast(URI lastLocation) {
+                last = lastLocation;
+            }
 
-        if (remaining.size() == 0 && server.getLocation() != null && !failed.contains(server.getLocation())){
-            return connect(cluster, server.getLocation());
-        }
+            @Override
+            public boolean hasNext() {
+                return first && last != null || getIterator().hasNext();
+            }
 
-        // If no servers responded, throw an error
-        StringBuilder buffer = new StringBuilder();
-        for (int i = 0; i < locations.length; i++) {
-            URI uri = locations[i];
-            buffer.append((i != 0 ? ", " : "") + "Server #" + i + ": " + uri);
-        }
-        throw new RemoteException("Cannot connect to any servers: " + buffer.toString());
-    }
+            @Override
+
+            public URI next() {
+                if (!hasNext()) throw new NoSuchElementException();
+
+                if (first && last != null) {
+                    first = false;
+                    return last;
+                }
 
-    protected Connection connect(ClusterMetaData cluster, URI uri) throws IOException {
-        Connection connection = ConnectionManager.getConnection(uri);
+                Iterator<URI> iterator = getIterator();
 
-        // Grabbing the URI from the associated connection allows the ConnectionFactory to
-        // employ discovery to find and connect to a server.  We then attempt to connect
-        // to the discovered server rather than repeat the discovery process again.
-        cluster.setLastLocation(connection.getURI());
-        return connection;
+                return iterator.next();
+            }
+
+            private Iterator<URI> getIterator() {
+                if (iterator == null) {
+                    iterator = iterable.iterator();
+                }
+                return iterator;
+            }
+
+            @Override
+            public void remove() {
+            }
+        }
     }
 
 }

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/BootstrappingConnection.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/BootstrappingConnection.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/BootstrappingConnection.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/BootstrappingConnection.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,39 @@
+/*
+ * 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.openejb.client.event;
+
+import java.net.URI;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Log(Log.Level.WARNING)
+public class BootstrappingConnection {
+
+    private final URI provider;
+
+    public BootstrappingConnection(URI provider) {
+        this.provider = provider;
+    }
+
+    @Override
+    public String toString() {
+        return "BootstrappingConnection{" +
+                "provider=" + provider +
+                '}';
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClientVersion.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClientVersion.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClientVersion.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClientVersion.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,74 @@
+/*
+ * 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.openejb.client.event;
+
+import org.apache.openejb.client.ResourceFinder;
+
+import java.util.Properties;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Log(Log.Level.CONFIG)
+public class ClientVersion {
+
+    private final String version;
+    private final String date;
+    private final String time;
+
+    public ClientVersion(String version, String date, String time) {
+        this.version = version;
+        this.date = date;
+        this.time = time;
+    }
+
+    public ClientVersion() {
+        Properties info = new Properties();
+
+        try {
+            ResourceFinder finder = new ResourceFinder();
+            info = finder.findProperties("openejb-client-version.properties");
+        } catch (java.io.IOException e) {
+            e.printStackTrace();
+        }
+
+        version = info.getProperty("version");
+        date = info.getProperty("date");
+        time = info.getProperty("time");
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getDate() {
+        return date;
+    }
+
+    public String getTime() {
+        return time;
+    }
+
+    @Override
+    public String toString() {
+        return "ClientVersion{" +
+                "version='" + version + '\'' +
+                ", date='" + date + '\'' +
+                ", time='" + time + '\'' +
+                '}';
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClusterMetaDataUpdated.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClusterMetaDataUpdated.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClusterMetaDataUpdated.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ClusterMetaDataUpdated.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,57 @@
+/*
+ * 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.openejb.client.event;
+
+import org.apache.openejb.client.ClusterMetaData;
+import org.apache.openejb.client.ServerMetaData;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ClusterMetaDataUpdated {
+
+    private final ServerMetaData serverMetaData;
+    private final ClusterMetaData clusterMetaData;
+    private final ClusterMetaData previousClusterMetaData;
+
+    public ClusterMetaDataUpdated(ServerMetaData serverMetaData, ClusterMetaData clusterMetaData, ClusterMetaData previousClusterMetaData) {
+        this.serverMetaData = serverMetaData;
+        this.clusterMetaData = clusterMetaData;
+        this.previousClusterMetaData = previousClusterMetaData;
+    }
+
+    public ServerMetaData getServerMetaData() {
+        return serverMetaData;
+    }
+
+    public ClusterMetaData getClusterMetaData() {
+        return clusterMetaData;
+    }
+
+    public ClusterMetaData getPreviousClusterMetaData() {
+        return previousClusterMetaData;
+    }
+
+    @Override
+    public String toString() {
+        return "ClusterMetaDataUpdated{" +
+                "provider=" + serverMetaData.getLocation() +
+                ", version=" + clusterMetaData.getVersion() +
+                ", uris=" + clusterMetaData.getLocations().length +
+                '}';
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryAdded.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryAdded.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryAdded.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryAdded.java Fri Mar 23 06:19:26 2012
@@ -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.openejb.client.event;
+
+import org.apache.openejb.client.ConnectionFactory;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Log(Log.Level.CONFIG)
+public class ConnectionFactoryAdded {
+
+    private String scheme;
+    private ConnectionFactory factory;
+
+    public ConnectionFactoryAdded(String scheme, ConnectionFactory factory) {
+        this.scheme = scheme;
+        this.factory = factory;
+    }
+
+    public String getScheme() {
+        return scheme;
+    }
+
+    public void setScheme(String scheme) {
+        this.scheme = scheme;
+    }
+
+    public ConnectionFactory getFactory() {
+        return factory;
+    }
+
+    public void setFactory(ConnectionFactory factory) {
+        this.factory = factory;
+    }
+
+    @Override
+    public String toString() {
+        return "ConnectionFactoryAdded{" +
+                "scheme='" + scheme + '\'' +
+                ", factory=" + factory.getClass().getName() +
+                '}';
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryRemoved.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryRemoved.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryRemoved.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFactoryRemoved.java Fri Mar 23 06:19:26 2012
@@ -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.openejb.client.event;
+
+import org.apache.openejb.client.ConnectionFactory;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Log(Log.Level.CONFIG)
+public class ConnectionFactoryRemoved {
+
+    private String scheme;
+    private ConnectionFactory factory;
+
+    public ConnectionFactoryRemoved(String scheme, ConnectionFactory factory) {
+        this.scheme = scheme;
+        this.factory = factory;
+    }
+
+    public String getScheme() {
+        return scheme;
+    }
+
+    public void setScheme(String scheme) {
+        this.scheme = scheme;
+    }
+
+    public ConnectionFactory getFactory() {
+        return factory;
+    }
+
+    public void setFactory(ConnectionFactory factory) {
+        this.factory = factory;
+    }
+
+    @Override
+    public String toString() {
+        return "ConnectionFactoryRemoved{" +
+                "scheme='" + scheme + '\'' +
+                ", factory=" + factory.getClass().getName() +
+                '}';
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFailed.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFailed.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFailed.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionFailed.java Fri Mar 23 06:19:26 2012
@@ -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.openejb.client.event;
+
+import java.net.URI;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Log(Log.Level.SEVERE)
+public class ConnectionFailed {
+    private final URI uri;
+    private final Throwable cause;
+
+    public ConnectionFailed(URI uri, Throwable cause) {
+        this.uri = uri;
+        this.cause = cause;
+    }
+
+    @Override
+    public String toString() {
+        return "ConnectionFailed{" +
+                "uri=" + uri +
+                '}';
+    }
+}

Added: openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionOpened.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionOpened.java?rev=1304199&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionOpened.java (added)
+++ openejb/branches/openejb-3.1.x/server/openejb-client/src/main/java/org/apache/openejb/client/event/ConnectionOpened.java Fri Mar 23 06:19:26 2012
@@ -0,0 +1,42 @@
+/*
+ * 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.openejb.client.event;
+
+import java.net.URI;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Log
+public class ConnectionOpened {
+    private final URI uri;
+
+    public ConnectionOpened(URI uri) {
+        this.uri = uri;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    @Override
+    public String toString() {
+        return "ConnectionOpened{" +
+                "uri=" + uri +
+                '}';
+    }
+}