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/02/20 11:35:47 UTC

svn commit: r1291185 - in /openejb/trunk/openejb: ./ arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/ container/openejb-core/src/main/java/org/apache/openejb/ container/openejb-core/src/main/java/org/apache/o...

Author: dblevins
Date: Mon Feb 20 10:35:46 2012
New Revision: 1291185

URL: http://svn.apache.org/viewvc?rev=1291185&view=rev
Log:
New module for testing failover capability.  Can unpack and setup several servers, deploy apps and stop/start them repeatedly.  Start waits for full startup via parsing server output.  All other commands wait for command completion.
OPENEJB-1782

Added:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/OutputScanner.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Tee.java
      - copied, changed from r1245753, openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Zips.java
    openejb/trunk/openejb/itests/failover/
    openejb/trunk/openejb/itests/failover-ejb/
    openejb/trunk/openejb/itests/failover-ejb/failover-ejb.iml
    openejb/trunk/openejb/itests/failover-ejb/pom.xml
    openejb/trunk/openejb/itests/failover-ejb/src/
    openejb/trunk/openejb/itests/failover-ejb/src/main/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/Calculator.java
    openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/CalculatorBean.java
    openejb/trunk/openejb/itests/failover/pom.xml   (with props)
    openejb/trunk/openejb/itests/failover/src/
    openejb/trunk/openejb/itests/failover/src/main/
    openejb/trunk/openejb/itests/failover/src/main/java/
    openejb/trunk/openejb/itests/failover/src/main/java/org/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/itest/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/itest/failover/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/control/
    openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/control/StandaloneServer.java
    openejb/trunk/openejb/itests/failover/src/main/resources/
    openejb/trunk/openejb/itests/failover/src/test/
    openejb/trunk/openejb/itests/failover/src/test/java/
    openejb/trunk/openejb/itests/failover/src/test/java/org/
    openejb/trunk/openejb/itests/failover/src/test/java/org/apache/
    openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/
    openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/
    openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/failover/
    openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/failover/FailoverTest.java
    openejb/trunk/openejb/itests/failover/src/test/resources/
Modified:
    openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Files.java
    openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Zips.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/EnvProps.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigUtils.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ConfUtils.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Files.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Join.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java
    openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/IO.java
    openejb/trunk/openejb/itests/pom.xml
    openejb/trunk/openejb/pom.xml
    openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
    openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceManager.java
    openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/SimpleServiceManager.java

Modified: openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Files.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Files.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Files.java (original)
+++ openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Files.java Mon Feb 20 10:35:46 2012
@@ -27,7 +27,11 @@ import java.util.List;
 public class Files {
 
     public static File createTempDir() throws IOException {
-        File tempDir = File.createTempFile("tomee", ".conf");
+        return createTempDir("tomee", ".conf");
+    }
+
+    public static File createTempDir(String prefix, String suffix) throws IOException {
+        File tempDir = File.createTempFile(prefix, suffix);
         tempDir.delete();
         tempDir.mkdirs();
         deleteOnExit(tempDir);

Modified: openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Zips.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Zips.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Zips.java (original)
+++ openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-common/src/main/java/org/apache/openejb/arquillian/common/Zips.java Mon Feb 20 10:35:46 2012
@@ -28,6 +28,11 @@ public class Zips {
     private static final Logger logger = Logger.getLogger(Zips.class.getName());
 
     public static void unzip(File zipFile, File destination) {
+        unzip(zipFile, destination, false);
+    }
+
+    public static void unzip(File zipFile, File destination, boolean noparent) {
+
         logger.info(String.format("Extracting '%s' to '%s'", zipFile.getAbsolutePath(), destination.getAbsolutePath()));
 
         Files.assertDir(destination);
@@ -43,7 +48,8 @@ public class Zips {
             ZipEntry entry;
 
             while ((entry = in.getNextEntry()) != null) {
-                final String path = entry.getName();
+                String path = entry.getName();
+                if (noparent) path = path.replaceFirst("^[^/]+/", "");
                 final File file = new File(destination, path);
 
                 if (entry.isDirectory()) {
@@ -53,6 +59,12 @@ public class Zips {
 
                 Files.mkdir(file.getParentFile());
                 IO.copy(in, file);
+
+                final long lastModified = entry.getTime();
+                if (lastModified > 0) {
+                    file.setLastModified(lastModified);
+                }
+
             }
 
             in.close();

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/EnvProps.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/EnvProps.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/EnvProps.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/EnvProps.java Mon Feb 20 10:35:46 2012
@@ -16,6 +16,8 @@
  */
 package org.apache.openejb;
 
+import org.apache.openejb.loader.SystemInstance;
+
 public class EnvProps {
 
     public final static String CONFIGURATION = "org/openejb/configuration_source";
@@ -23,4 +25,10 @@ public class EnvProps {
     public final static String CONFIGURATION_FACTORY = "org/openejb/configuration_factory";
     public final static String DEPLOYED_RAR_DIRECTORY = "org/openejb/assembler/rar_directory";
     public final static String DEPLOYED_JAR_DIRECTORY = "org/openejb/assembler/jar_directory";
+    public final static String AUTO_CONFIGURE = "openejb.extract.configuration";
+
+
+    public static boolean extractConfigurationFiles() {
+        return SystemInstance.get().getOptions().get(AUTO_CONFIGURE, true);
+    }
 }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigUtils.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigUtils.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigUtils.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigUtils.java Mon Feb 20 10:35:46 2012
@@ -16,10 +16,12 @@
  */
 package org.apache.openejb.config;
 
+import org.apache.openejb.EnvProps;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.config.sys.Deployments;
 import org.apache.openejb.config.sys.Openejb;
 import org.apache.openejb.config.sys.JaxbOpenejb;
+import org.apache.openejb.loader.IO;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
@@ -28,10 +30,7 @@ import org.apache.xbean.finder.ResourceF
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Properties;
@@ -133,24 +132,22 @@ public class ConfigUtils {
             }
 
 
-            /* [6] No config found! Create a config for them
-             *     using the default.openejb.conf file from 
-             *     the openejb-x.x.x.jar
-             */
-
-            File confDir = SystemInstance.get().getBase().getDirectory("conf", false);
-
-            // TODO: DMB: This logic needs to be revisited 
-            if (confDir.exists()) {
-                File config = new File(confDir, "openejb.xml");
-                logger.info("Cannot find the configuration file [conf/openejb.xml].  Creating one at "+config.getAbsolutePath());
-                file = createConfig(config);
-            } else {
-                logger.info("Cannot find the configuration file [conf/openejb.xml].  Will attempt to create one for the beans deployed.");
-//                logger.warning("Cannot find the configuration file [conf/openejb.xml].  Using the default configuration.");
-//                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-//                URL resource = classLoader.getResource("default.openejb.conf");
-//                return resource.toExternalForm();
+            if (EnvProps.extractConfigurationFiles()) {
+
+                /* [6] No config found! Create a config for them
+                 *     using the default.openejb.conf file from
+                 *     the openejb-x.x.x.jar
+                 */
+
+                final File confDir = SystemInstance.get().getBase().getDirectory("conf", false);
+
+                if (confDir.exists()) {
+                    File config = new File(confDir, "openejb.xml");
+                    logger.info("Cannot find the configuration file [conf/openejb.xml].  Creating one at "+config.getAbsolutePath());
+                    file = createConfig(config);
+                } else {
+                    logger.info("Cannot find the configuration file [conf/openejb.xml].  Will attempt to create one for the beans deployed.");
+                }
             }
 
         } catch (java.io.IOException e) {
@@ -158,35 +155,15 @@ public class ConfigUtils {
             throw new OpenEJBException("Could not locate config file: ", e);
         }
 
-        /*TODO:2: Check these too.
-        * OPENJB_HOME/lib/openejb-x.x.x.jar
-        * OPENJB_HOME/dist/openejb-x.x.x.jar
-        */
         return (file == null) ? null : file.getAbsolutePath();
     }
 
     public static File createConfig(File config) throws java.io.IOException {
-        InputStream in = null;
-        OutputStream out = null;
-        try {
-            ResourceFinder finder = new ResourceFinder("");
-            URL defaultConfig = finder.find("default.openejb.conf");
-            in = defaultConfig.openStream();
-            out = new FileOutputStream(config);
-
-            int b;
-            while ((b = in.read()) != -1) {
-                out.write(b);
-            }
-        } finally {
-            if (in != null) {
-                in.close();
-            }
-            if (out != null) {
-                out.close();
-            }
+        ResourceFinder finder = new ResourceFinder("");
+        URL defaultConfig = finder.find("default.openejb.conf");
+
+        IO.copy(defaultConfig.openStream(), config);
 
-        }
         return config;
     }
 

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ConfUtils.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ConfUtils.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ConfUtils.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ConfUtils.java Mon Feb 20 10:35:46 2012
@@ -16,15 +16,13 @@
  */
 package org.apache.openejb.util;
 
+import org.apache.openejb.EnvProps;
 import org.apache.openejb.loader.FileUtils;
+import org.apache.openejb.loader.IO;
 import org.apache.openejb.loader.SystemInstance;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.URL;
 import java.util.Enumeration;
 import java.util.Collections;
@@ -38,6 +36,8 @@ public class ConfUtils {
     public static URL getConfResource(String name) {
         URL resource = getResource(name);
 
+        if (!EnvProps.extractConfigurationFiles()) return resource;
+
         try {
 
             File loginConfig = ConfUtils.install(resource, name);
@@ -100,28 +100,7 @@ public class ConfUtils {
 
         if (file.exists() && !overwrite) return file;
 
-        InputStream in = resource.openStream();
-        in = new BufferedInputStream(in);
-
-        FileOutputStream fout = new FileOutputStream(file);
-        BufferedOutputStream out = new BufferedOutputStream(fout);
-
-        try {
-            int b = in.read();
-            while (b != -1) {
-                out.write(b);
-                b = in.read();
-            }
-        } finally {
-            try {
-                in.close();
-            } catch (IOException e) {
-            }
-            try {
-                out.close();
-            } catch (IOException e) {
-            }
-        }
+        IO.copy(resource.openStream(), file);
 
         return file;
     }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Files.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Files.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Files.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Files.java Mon Feb 20 10:35:46 2012
@@ -57,7 +57,7 @@ public class Files {
         return collect(dir, new FileFilter() {
             @Override
             public boolean accept(File file) {
-                return pattern.matcher(file.getAbsolutePath()).matches();
+                return pattern.matcher(file.getName()).matches();
             }
         });
     }
@@ -80,6 +80,11 @@ public class Files {
         return file;
     }
 
+    public static File exists(File file) {
+        if (!file.exists()) throw new RuntimeException("Does not exist: " + file.getAbsolutePath());
+        return file;
+    }
+
     public static File dir(File file) {
         if (!file.isDirectory()) throw new RuntimeException("Not a directory: " + file.getAbsolutePath());
         return file;
@@ -170,4 +175,10 @@ public class Files {
         }
     }
 
+    public static File select(File dir, String pattern) {
+        final List<File> matches = collect(dir, pattern);
+        if (matches.size() == 0) throw new IllegalStateException(String.format("Missing '%s'", pattern));
+        if (matches.size() > 1) throw new IllegalStateException(String.format("Too many found '%s': %s", Join.join(", ", new Join.FileCallback(), matches)));
+        return matches.get(0);
+    }
 }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Join.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Join.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Join.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Join.java Mon Feb 20 10:35:46 2012
@@ -16,8 +16,11 @@
  */
 package org.apache.openejb.util;
 
+import java.io.File;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * @version $Rev$ $Date$
@@ -72,11 +75,29 @@ public class Join {
         return sb.substring(0, sb.length() - delimiter.length());
     }
 
+    public static <T> List<String> strings(Collection<T> collection, NameCallback<T> callback) {
+        final List<String> list = new ArrayList<String>();
+
+        for (T t : collection) {
+            final String name = callback.getName(t);
+            list.add(name);
+        }
+
+        return list;
+    }
+
     public static interface NameCallback<T> {
 
         public String getName(T object);
     }
 
+    public static class FileCallback implements NameCallback<File> {
+
+        public String getName(File file) {
+            return file.getName();
+        }
+    }
+
     public static class MethodCallback implements NameCallback<Method> {
 
         public String getName(Method method) {

Added: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/OutputScanner.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/OutputScanner.java?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/OutputScanner.java (added)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/OutputScanner.java Mon Feb 20 10:35:46 2012
@@ -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.openejb.util;
+
+import org.codehaus.swizzle.stream.ScanBuffer;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class OutputScanner extends FilterOutputStream {
+
+    private final CountDownLatch found = new CountDownLatch(1);
+
+    public OutputScanner(OutputStream out, String scanString) {
+        super(null);
+        this.out = new Scan(out, scanString);
+    }
+
+    public class Scan extends FilterOutputStream {
+
+        private final ScanBuffer scan;
+
+        public Scan(OutputStream out, String scanString) {
+            super(out);
+            scan = new ScanBuffer(scanString);
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            check(b);
+            super.write(b);
+        }
+
+        @Override
+        public void write(byte[] bytes) throws IOException {
+            for (byte b : bytes) {
+                check(b);
+            }
+            super.write(bytes);
+        }
+
+        @Override
+        public void write(byte[] bytes, int off, int len) throws IOException {
+            for (int i = off; i < len; i++) {
+                check(bytes[i]);
+            }
+            super.write(bytes, off, len);
+        }
+
+        private void check(int b) {
+            scan.append(b);
+            if (scan.match()) {
+                // Cut ourselves out of the call chain.
+                //
+                // This works because
+                //  - ScanningOutputStreamFilter.this.out == this
+                //  - this.out != this)
+                //
+                // Our parent is delegating to us and we are delegating
+                // to the actual OutputStream
+                //
+                // To cut ourselves out of the call chain and eliminate
+                // the overhead of checking the ScanBuffer, we set our
+                // parent to not delegate to us and to instead delegate
+                // to the actual OutputStream.
+
+                // Intellij mistakenly shows this grayed out,
+                // however it is very very significant.
+                OutputScanner.this.out = this.out;
+                found.countDown();
+            }
+        }
+    }
+
+
+    public void await() throws InterruptedException {
+        found.await();
+    }
+
+    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
+        return found.await(timeout, unit);
+    }
+}

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java Mon Feb 20 10:35:46 2012
@@ -39,6 +39,11 @@ public final class Pipe implements Runna
         pipe(System.in, process.getOutputStream());
     }
 
+    public static void read(Process process) {
+        pipe(process.getInputStream(), System.out);
+        pipe(process.getErrorStream(), System.err);
+    }
+
     public static void pipe(InputStream in, OutputStream out) {
         final Thread thread = new Thread(new Pipe(in, out));
         thread.setDaemon(true);
@@ -49,7 +54,7 @@ public final class Pipe implements Runna
         try {
             int i = -1;
 
-            byte[] buf = new byte[1024];
+            byte[] buf = new byte[1];
 
             while ((i = in.read(buf)) != -1) {
                 out.write(buf, 0, i);

Copied: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Tee.java (from r1245753, openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java)
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Tee.java?p2=openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Tee.java&p1=openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java&r1=1245753&r2=1291185&rev=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Pipe.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Tee.java Mon Feb 20 10:35:46 2012
@@ -17,30 +17,46 @@
 
 package org.apache.openejb.util;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
 
 /**
  * @version $Rev$ $Date$
  */
-public final class Pipe implements Runnable {
+public final class Tee implements Runnable {
 
     private final InputStream in;
-    private final OutputStream out;
+    private final OutputStream[] out;
 
-    public Pipe(InputStream in, OutputStream out) {
+    public Tee(InputStream in, OutputStream... out) {
         this.in = in;
         this.out = out;
     }
 
-    public static void pipe(Process process) {
-        pipe(process.getInputStream(), System.out);
-        pipe(process.getErrorStream(), System.err);
-        pipe(System.in, process.getOutputStream());
+    public static InputStream read(Process process) {
+//        pipe(process.getErrorStream(), System.err);
+        return process.getInputStream();
+
+//        try {
+//
+//            final PipedOutputStream pipe = new PipedOutputStream();
+//            final PipedInputStream snk = new PipedInputStream(pipe, 32*32*32);
+//            run(new Tee(process.getInputStream(), System.out, pipe));
+//            return snk;
+//        } catch (IOException e) {
+//            throw new IllegalStateException(e);
+//        }
     }
 
     public static void pipe(InputStream in, OutputStream out) {
-        final Thread thread = new Thread(new Pipe(in, out));
+        run(new Tee(in, out));
+    }
+
+    private static void run(Tee target) {
+        final Thread thread = new Thread(target);
         thread.setDaemon(true);
         thread.start();
     }
@@ -49,13 +65,23 @@ public final class Pipe implements Runna
         try {
             int i = -1;
 
-            byte[] buf = new byte[1024];
+            final byte[] buf = new byte[32*32*32];
 
             while ((i = in.read(buf)) != -1) {
-                out.write(buf, 0, i);
+                System.out.print("#");
+                for (int o = 0; o < out.length; o++) {
+                    try {
+                        if (out[o] == null) continue;
+                        out[o].write(buf, 0, i);
+                    } catch (Exception e) {
+                        new Exception(out[o].toString(), e).printStackTrace();
+                        out[o] = null;
+                    }
+                }
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
+
 }

Added: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Zips.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Zips.java?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Zips.java (added)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Zips.java Mon Feb 20 10:35:46 2012
@@ -0,0 +1,73 @@
+/*
+ * 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.util;
+
+import org.apache.openejb.loader.IO;
+
+import java.io.File;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class Zips {
+    public static void unzip(File zipFile, File destination) {
+        unzip(zipFile, destination, false);
+    }
+
+    public static void unzip(File zipFile, File destination, boolean noparent) {
+
+        Files.dir(destination);
+        Files.writable(destination);
+
+        Files.file(zipFile);
+        Files.readable(zipFile);
+
+        try {
+            // Open the ZIP file
+            final ZipInputStream in = IO.unzip(zipFile);
+
+            ZipEntry entry;
+
+            while ((entry = in.getNextEntry()) != null) {
+                String path = entry.getName();
+                if (noparent) path = path.replaceFirst("^[^/]+/", "");
+                final File file = new File(destination, path);
+
+                if (entry.isDirectory()) {
+                    Files.mkdir(file);
+                    continue;
+                }
+
+                Files.mkdir(file.getParentFile());
+                IO.copy(in, file);
+
+                final long lastModified = entry.getTime();
+                if (lastModified > 0) {
+                    file.setLastModified(lastModified);
+                }
+
+            }
+
+            in.close();
+
+        } catch (Exception e) {
+            throw new IllegalStateException("Unable to unzip " + zipFile.getAbsolutePath(), e);
+        }
+    }
+}

Modified: openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/IO.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/IO.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/IO.java (original)
+++ openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/IO.java Mon Feb 20 10:35:46 2012
@@ -20,6 +20,7 @@ import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
@@ -33,6 +34,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.Proxy;
 import java.net.ProxySelector;
 import java.net.URI;
@@ -257,4 +259,16 @@ public class IO {
         final InputStream in = new FileInputStream(source);
         return new BufferedInputStream(in, 32768);
     }
+
+    public static InputStream read(String content) {
+        return read(content.getBytes());
+    }
+
+    public static InputStream read(String content, String encoding) throws UnsupportedEncodingException {
+        return read(content.getBytes(encoding));
+    }
+
+    public static InputStream read(byte[] content) {
+        return new ByteArrayInputStream(content);
+    }
 }
\ No newline at end of file

Added: openejb/trunk/openejb/itests/failover-ejb/failover-ejb.iml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover-ejb/failover-ejb.iml?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover-ejb/failover-ejb.iml (added)
+++ openejb/trunk/openejb/itests/failover-ejb/failover-ejb.iml Mon Feb 20 10:35:46 2012
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Maven: org.apache.openejb:javaee-api:6.0-3" level="project" />
+    <orderEntry type="library" name="Maven: junit:junit:4.9" level="project" />
+    <orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
+  </component>
+</module>
+

Added: openejb/trunk/openejb/itests/failover-ejb/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover-ejb/pom.xml?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover-ejb/pom.xml (added)
+++ openejb/trunk/openejb/itests/failover-ejb/pom.xml Mon Feb 20 10:35:46 2012
@@ -0,0 +1,43 @@
+<?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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>itests</artifactId>
+    <groupId>org.apache.openejb</groupId>
+    <version>4.0.0-beta-3-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.openejb.itests</groupId>
+  <artifactId>failover-ejb</artifactId>
+  <packaging>jar</packaging>
+  <name>OpenEJB :: iTests Beans</name>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>javaee-api</artifactId>
+      <version>6.0-3</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
+

Added: openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/Calculator.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/Calculator.java?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/Calculator.java (added)
+++ openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/Calculator.java Mon Feb 20 10:35:46 2012
@@ -0,0 +1,26 @@
+/*
+ * 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.itest.failover.ejb;
+
+import javax.ejb.Remote;
+
+@Remote
+public interface Calculator {
+
+    int sum(int a, int b);
+
+}

Added: openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/CalculatorBean.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/CalculatorBean.java?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/CalculatorBean.java (added)
+++ openejb/trunk/openejb/itests/failover-ejb/src/main/java/org/apache/openejb/itest/failover/ejb/CalculatorBean.java Mon Feb 20 10:35:46 2012
@@ -0,0 +1,28 @@
+/*
+ * 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.itest.failover.ejb;
+
+import javax.ejb.Stateless;
+
+@Stateless
+public class CalculatorBean implements Calculator {
+
+    @Override
+    public int sum(int a, int b) {
+        return a + b;
+    }
+}

Added: openejb/trunk/openejb/itests/failover/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover/pom.xml?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover/pom.xml (added)
+++ openejb/trunk/openejb/itests/failover/pom.xml Mon Feb 20 10:35:46 2012
@@ -0,0 +1,64 @@
+<?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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>itests</artifactId>
+    <groupId>org.apache.openejb</groupId>
+    <version>4.0.0-beta-3-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.openejb.itests</groupId>
+  <artifactId>failover</artifactId>
+  <packaging>jar</packaging>
+  <name>OpenEJB :: iTests Beans</name>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>openejb-standalone</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>openejb-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>openejb-client</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb.itests</groupId>
+      <artifactId>failover-ejb</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>arquillian-tomee-common</artifactId>
+      <version>1.0.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
+

Propchange: openejb/trunk/openejb/itests/failover/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/control/StandaloneServer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/control/StandaloneServer.java?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/control/StandaloneServer.java (added)
+++ openejb/trunk/openejb/itests/failover/src/main/java/org/apache/openejb/server/control/StandaloneServer.java Mon Feb 20 10:35:46 2012
@@ -0,0 +1,408 @@
+/*
+ * 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.server.control;
+
+import org.apache.openejb.client.Options;
+import org.apache.openejb.util.Files;
+import org.apache.openejb.util.Join;
+import org.apache.openejb.util.OutputScanner;
+import org.apache.openejb.util.Pipe;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.openejb.util.Files.dir;
+import static org.apache.openejb.util.Files.exists;
+import static org.apache.openejb.util.Files.file;
+import static org.apache.openejb.util.Files.readable;
+import static org.apache.openejb.util.Files.select;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class StandaloneServer {
+
+    private final File home;
+    private final File base;
+    private final File java;
+    private final File openejbJar;
+    private boolean debug;
+    private boolean profile;
+    private volatile Process process;
+    private final List<String> jvmOpts = new ArrayList<String>();
+    private final Properties properties = new Properties();
+    private boolean verbose = false;
+    private OutputStream out = System.out;
+    private Options options = new Options(properties);
+
+    public StandaloneServer(File home, File base) {
+        this.home = home;
+        this.base = base;
+
+        final File lib = readable(dir(exists(new File(home, "lib"))));
+
+        openejbJar = readable(file(select(lib, "openejb-core.*.jar")));
+        final File javaagentJar = readable(file(select(lib, "openejb-javaagent.*.jar")));
+
+        final File javaHome = readable(dir(exists(new File(System.getProperty("java.home")))));
+
+        java = readable(file(Files.path(javaHome, "bin", "java")));
+
+        jvmOpts.add("-XX:+HeapDumpOnOutOfMemoryError");
+        jvmOpts.add("-javaagent:" + javaagentJar.getAbsolutePath());
+    }
+
+    public ServerService getServerService(String string) {
+        return new ServerService(string);
+    }
+
+    public class ServerService {
+
+        private String bind;
+        private int threads;
+
+        private final String name;
+
+        public ServerService(String name) {
+            this.name = name;
+        }
+
+        public int getPort() {
+            return options.get(name + ".port", -1);
+        }
+
+        public void setPort(int i) {
+            properties.put(name + ".port", i + "");
+        }
+
+        public boolean isDisabled() {
+            return options.get(name + ".disabled", true);
+        }
+
+        public void setDisabled(boolean b) {
+            properties.put(name + ".disabled", b + "");
+        }
+
+        public String getBind() {
+            return options.get(name + ".bind", "");
+        }
+
+        public void setBind(String bind) {
+            properties.put(name + ".bind", bind);
+        }
+
+        public int getThreads() {
+            return options.get(name + ".threads", -1);
+        }
+
+        public void setThreads(int threads) {
+            properties.put(name + ".threads", threads + "");
+        }
+
+        public void set(String name, String value) {
+            properties.put(this.name + "." + name, value);
+        }
+    }
+
+    public File getHome() {
+        return home;
+    }
+
+    public File getBase() {
+        return base;
+    }
+
+    public boolean isDebug() {
+        return debug;
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public boolean isProfile() {
+        return profile;
+    }
+
+    public void setProfile(boolean profile) {
+        this.profile = profile;
+    }
+
+    public Process getProcess() {
+        return process;
+    }
+
+    public void setProcess(Process process) {
+        this.process = process;
+    }
+
+    public boolean isVerbose() {
+        return verbose;
+    }
+
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    public OutputStream getOut() {
+        return out;
+    }
+
+    public void setOut(OutputStream out) {
+        this.out = out;
+    }
+
+    public void ignoreOut() {
+        setOut(new DevNull());
+    }
+
+    public List<String> getJvmOpts() {
+        return jvmOpts;
+    }
+
+    public Properties getProperties() {
+        return properties;
+    }
+
+    public void start() {
+        start(0, TimeUnit.MILLISECONDS);
+    }
+
+    public void start(int timeout, TimeUnit minutes) {
+        if (process != null) throw new ServerRunningException(home, "Server already running");
+
+        try {
+            List<String> args = new ArrayList<String>();
+            args.add(java.getAbsolutePath());
+            args.addAll(jvmOpts);
+            final Set<Map.Entry<Object, Object>> collection = properties.entrySet();
+            args.addAll(Join.strings(collection, new SystemPropertiesCallback()));
+
+            args.add("-jar");
+            args.add(openejbJar.getAbsolutePath());
+            args.add("start");
+
+            final ProcessBuilder builder = new ProcessBuilder(args);
+            builder.redirectErrorStream(true);
+
+            if (verbose) {
+                System.out.println(Join.join("\n", args));
+            }
+
+            process = builder.start();
+
+            if (timeout > 0) {
+                final OutputScanner scanner = new OutputScanner(out, "Ready!");
+                Pipe.pipe(process.getInputStream(), scanner);
+                scanner.await(timeout, minutes);
+            } else {
+                out = System.out;
+                Pipe.pipe(process.getInputStream(), out);
+            }
+        } catch (InterruptedException e) {
+            Thread.interrupted();
+            throw new IllegalStateException("Server failed to start in the expected time");
+        } catch (IOException e) {
+            throw new IllegalStateException("Server did not start correctly", e);
+        }
+    }
+
+    private void edit() {
+        if (process != null) throw new ServerRunningException(home, "Cannot change settings while server is running");
+    }
+
+    public static class DevNull extends OutputStream {
+
+        @Override
+        public void write(int b) throws IOException {
+        }
+    }
+
+    public void kill() {
+        if (process == null) return;
+
+        process.destroy();
+
+        waitForExit();
+    }
+
+    private void waitForExit() {
+        kill.remove(this);
+        try {
+            process.waitFor();
+        } catch (InterruptedException e) {
+            Thread.interrupted();
+        }
+        process = null;
+    }
+
+    private int command(String... strings) {
+        return command(Arrays.asList(strings));
+    }
+
+    private int command(List<String> strings) {
+        if (process == null) throw new ServerNotRunningException(home);
+
+        try {
+            final List<String> args = new ArrayList<String>();
+            args.add(java.getAbsolutePath());
+            args.add("-jar");
+            args.add(openejbJar.getAbsolutePath());
+            args.addAll(strings);
+
+            final ProcessBuilder builder = new ProcessBuilder(args);
+            final Process command = builder.start();
+            Pipe.read(command);
+            return command.waitFor();
+        } catch (IOException e) {
+            throw new ServerException(home, Join.join(" ", strings), e);
+        } catch (InterruptedException e) {
+            Thread.interrupted();
+        }
+        return -1;
+    }
+
+    public void deploy(String path) {
+        final int code = command("deploy", path);
+        if (code != 0) {
+            throw new DeployException(home, code, path);
+        }
+    }
+
+    public void undeploy(String path) {
+        final int code = command("undeploy", path);
+        if (code != 0) {
+            throw new UndeployException(home, code, path);
+        }
+    }
+
+    public void stop() {
+        final int code = command("stop");
+        if (code != 0) {
+            throw new StopException(home, code);
+        }
+        waitForExit();
+    }
+
+
+    public void killOnExit() {
+        kill.add(this);
+    }
+
+    // Shutdown hook for recursive delete on tmp directories
+    static final List<StandaloneServer> kill = new ArrayList<StandaloneServer>();
+
+    static {
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                for (StandaloneServer server : kill) {
+                    try {
+                        if (server.process != null) {
+                            server.process.destroy();
+                        }
+                    } catch (Throwable e) {
+                    }
+                }
+            }
+        });
+    }
+
+    public static class ServerException extends RuntimeException {
+        private final File home;
+
+        public ServerException(File home) {
+            this.home = home;
+        }
+
+        public ServerException(File home, String message) {
+            super(message);
+            this.home = home;
+        }
+
+        public ServerException(File home, String message, Throwable cause) {
+            super(message, cause);
+            this.home = home;
+        }
+
+        @Override
+        public String getMessage() {
+            return super.getMessage() + String.format("server path `%s`", home.getAbsolutePath());
+        }
+    }
+
+    public static class ServerNotRunningException extends ServerException {
+        public ServerNotRunningException(File home) {
+            super(home);
+        }
+    }
+
+    public static class ServerRunningException extends ServerException {
+        public ServerRunningException(File home) {
+            super(home);
+        }
+
+        public ServerRunningException(File home, String message) {
+            super(home, message);
+        }
+    }
+
+    public static class ServerCommandException extends ServerException {
+        private final int returnCode;
+        private final String[] args;
+
+        public ServerCommandException(File home, int returnCode, String... args) {
+            super(home);
+            this.returnCode = returnCode;
+            this.args = args;
+        }
+    }
+
+    public static class DeployException extends ServerCommandException {
+        public DeployException(File home, int returnCode, String... args) {
+            super(home, returnCode, args);
+        }
+    }
+
+    public static class UndeployException extends ServerCommandException {
+        public UndeployException(File home, int returnCode, String... args) {
+            super(home, returnCode, args);
+        }
+    }
+
+    public static class StopException extends ServerCommandException {
+        public StopException(File home, int returnCode, String... args) {
+            super(home, returnCode, args);
+        }
+    }
+
+    private static class SystemPropertiesCallback implements Join.NameCallback<Map.Entry<Object, Object>> {
+        @Override
+        public String getName(Map.Entry<Object, Object> e) {
+            return String.format("-D%s=%s", e.getKey().toString(), e.getValue().toString());
+        }
+    }
+
+}

Added: openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/failover/FailoverTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/failover/FailoverTest.java?rev=1291185&view=auto
==============================================================================
--- openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/failover/FailoverTest.java (added)
+++ openejb/trunk/openejb/itests/failover/src/test/java/org/apache/openejb/itest/failover/FailoverTest.java Mon Feb 20 10:35:46 2012
@@ -0,0 +1,180 @@
+/*
+ * 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.itest.failover;
+
+import org.apache.openejb.client.RemoteInitialContextFactory;
+import org.apache.openejb.itest.failover.ejb.Calculator;
+import org.apache.openejb.loader.IO;
+import org.apache.openejb.server.control.StandaloneServer;
+import org.apache.openejb.util.Files;
+import org.apache.openejb.util.Join;
+import org.apache.openejb.util.Zips;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import javax.ejb.EJBException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+public class FailoverTest {
+
+    @Test
+    public void testNothing() {
+    }
+
+    @Test @Ignore
+    public void testFailover() throws Exception {
+
+        final File zip = new File("/Users/dblevins/.m2/repository/org/apache/openejb/openejb-standalone/4.0.0-beta-3-SNAPSHOT/openejb-standalone-4.0.0-beta-3-SNAPSHOT.zip");
+        final File app = new File("/Users/dblevins/.m2/repository/org/apache/openejb/itests/failover-ejb/4.0.0-beta-3-SNAPSHOT/failover-ejb-4.0.0-beta-3-SNAPSHOT.jar");
+
+        final File dir = Files.tmpdir();
+
+        final String[] serverNames = {"red", "green", "blue"};
+//        final String[] serverNames = {"red", "green", "blue", "yellow", "orange", "purple"};
+//        final String[] serverNames = {"red", "green"};
+
+        final List<StandaloneServer> servers = new ArrayList<StandaloneServer>();
+
+        final List<String> initialServers = new ArrayList<String>();
+
+        for (String name : serverNames) {
+            final File home = new File(dir, name);
+            Files.mkdir(home);
+            Zips.unzip(zip, home, true);
+
+            final StandaloneServer server = new StandaloneServer(home, home);
+            server.killOnExit();
+            server.ignoreOut();
+            server.getProperties().put("openejb.extract.configuration", "false");
+
+            IO.copy(app, Files.path(home, "apps", "itest.jar"));
+            IO.copy(IO.read("<openejb><Deployments dir=\"apps/\"/></openejb>"), Files.path(home, "conf", "openejb.xml"));
+            /*
+            server      = org.apache.openejb.server.ejbd.EjbServer
+            bind        = 127.0.0.1
+            port        = 4201
+            disabled    = false
+            threads     = 200
+            backlog     = 200
+            discovery   = ejb:ejbd://{bind}:{port}
+             */
+            final StandaloneServer.ServerService ejbd = server.getServerService("ejbd");
+            ejbd.setDisabled(false);
+            ejbd.setPort(getAvailablePort());
+            ejbd.setThreads(5);
+            ejbd.set("discovery", "ejb:ejbd://{bind}:{port}/" + name);
+
+            /*
+            server      = org.apache.openejb.server.discovery.MultipointDiscoveryAgent
+            bind        = 127.0.0.1
+            port        = 4212
+            disabled    = true
+
+            initialServers         =
+            group                  = default
+            heart_rate             = 500
+            loopback_mode          = false
+            max_missed_heartbeats  = 10
+             */
+            final StandaloneServer.ServerService multipoint = server.getServerService("multipoint");
+            multipoint.setPort(getAvailablePort());
+            multipoint.setDisabled(false);
+
+            initialServers.add("localhost:" + multipoint.getPort());
+
+            servers.add(server);
+        }
+
+        servers.get(0).setOut(System.out);
+
+        for (StandaloneServer server : servers) {
+            final StandaloneServer.ServerService multipoint = server.getServerService("multipoint");
+            multipoint.set("initialServers", Join.join(",", initialServers));
+        }
+
+        for (StandaloneServer server : servers) {
+            server.start(1, TimeUnit.MINUTES);
+        }
+
+        Collections.reverse(servers);
+
+        System.setProperty("openejb.client.requestretry", "true");
+
+        final Properties environment = new Properties();
+        environment.put(Context.INITIAL_CONTEXT_FACTORY, RemoteInitialContextFactory.class.getName());
+        environment.put(Context.PROVIDER_URL, "failover:ejbd://localhost:" + servers.get(0).getServerService("ejbd").getPort());
+
+        final InitialContext context = new InitialContext(environment);
+        final Calculator bean = (Calculator) context.lookup("CalculatorBeanRemote");
+
+        for (StandaloneServer server : servers) {
+            System.out.println(String.format("Average invocation time %s microseconds", invoke(bean, 10000)));
+            server.kill();
+        }
+
+        System.out.println("All servers destroyed");
+
+        try {
+            System.out.println(String.format("Average invocation time %s microseconds", invoke(bean, 10000)));
+            Assert.fail("Server should be destroyed");
+        } catch (EJBException e) {
+            // good
+        }
+
+        for (StandaloneServer server : servers) {
+            server.start(1, TimeUnit.MINUTES);
+            System.out.println(String.format("Average invocation time %s microseconds", invoke(bean, 10000)));
+        }
+
+        System.out.println("DONE");
+    }
+
+    private long invoke(Calculator bean, int max) {
+
+        long total = 0;
+
+        for (int i = 0; i < max; i++) {
+            final long start = System.nanoTime();
+            Assert.assertEquals(3, bean.sum(1, 2));
+            total += System.nanoTime() - start;
+        }
+
+        return TimeUnit.NANOSECONDS.toMicros(total / max);
+    }
+
+    private int getAvailablePort() {
+        try {
+            final ServerSocket serverSocket = new ServerSocket(0);
+            final int port = serverSocket.getLocalPort();
+            serverSocket.close();
+
+            return port;
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to acquire a available port");
+        }
+    }
+}

Modified: openejb/trunk/openejb/itests/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/itests/pom.xml?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/itests/pom.xml (original)
+++ openejb/trunk/openejb/itests/pom.xml Mon Feb 20 10:35:46 2012
@@ -36,6 +36,8 @@
     <module>openejb-itests-interceptor-beans</module>
     <module>openejb-itests-app</module>
     <module>openejb-itests-web</module>
+    <module>failover</module>
+    <module>failover-ejb</module>
   </modules>
 </project>
 

Modified: openejb/trunk/openejb/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/pom.xml?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/pom.xml (original)
+++ openejb/trunk/openejb/pom.xml Mon Feb 20 10:35:46 2012
@@ -1163,7 +1163,7 @@
       <dependency>
         <groupId>org.codehaus.swizzle</groupId>
         <artifactId>swizzle-stream</artifactId>
-        <version>1.0.2</version>
+        <version>1.6.1</version>
       </dependency>
       <!--  <dependency>
        <groupId>org.apache.openejb</groupId>

Modified: openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java (original)
+++ openejb/trunk/openejb/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java Mon Feb 20 10:35:46 2012
@@ -82,16 +82,19 @@ public class Client {
     }
 
     protected Response processRequest(Request req, Response res, ServerMetaData server, URI preferredServerURI) throws RemoteException {
-        if (server == null)
+        if (server == null){
             throw new IllegalArgumentException("Server instance cannot be null");
+        }
+
+        final long start = System.nanoTime();
 
-        ClusterMetaData cluster = getClusterMetaData(server);
+        final ClusterMetaData cluster = getClusterMetaData(server);
 
         /*----------------------------*/
         /* Get a connection to server */
         /*----------------------------*/
 
-        Connection conn;
+        final Connection conn;
         try {
             if (preferredServerURI != null) {
                 conn = ConnectionManager.getConnection(preferredServerURI);
@@ -286,11 +289,20 @@ public class Client {
                     }
                 }
             }
+
+            final long time = System.nanoTime() - start;
+
         } catch (RemoteException e) {
             throw e;
         } catch (IOException e){
-            Set<URI> failed = getFailed();
-            failed.add(conn.getURI());
+            final URI uri = conn.getURI();
+            final Set<URI> failed = getFailed();
+            final Level level = Level.FINER;
+
+            if (logger.isLoggable(level)) {
+                logger.log(level, "Add Failed " + uri.toString());
+            }
+            failed.add(uri);
             conn.discard();
             //If the preferred server URI is configured, we will not try to fail over to other servers
             //Currently, while calling Future.cancel method remotely, the initial business method invocation server URI should be used.
@@ -351,6 +363,12 @@ public class Client {
     private static final Map<ServerMetaData, ClusterMetaData> clusters = new ConcurrentHashMap<ServerMetaData, ClusterMetaData>();
 
     private static void setClusterMetaData(ServerMetaData server, ClusterMetaData cluster) {
+        final Level level = Level.INFO;
+
+        if (logger.isLoggable(level)) {
+            logger.log(level, "Update ClusterMetaData(version=" + cluster.getVersion() + ", uris=" + cluster.getLocations().length);
+        }
+
         clusters.put(server, cluster);
     }
 

Modified: openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceManager.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceManager.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceManager.java (original)
+++ openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceManager.java Mon Feb 20 10:35:46 2012
@@ -18,7 +18,6 @@ package org.apache.openejb.server;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -26,9 +25,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.openejb.EnvProps;
 import org.apache.openejb.assembler.classic.OpenEjbConfiguration;
 import org.apache.openejb.assembler.classic.ServiceInfo;
 import org.apache.openejb.loader.FileUtils;
+import org.apache.openejb.loader.IO;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
@@ -162,10 +163,10 @@ public abstract class ServiceManager {
     }
 
     private void overrideProperties(String serviceName, Properties serviceProperties) throws IOException {
-        FileUtils base = SystemInstance.get().getBase();
+        final FileUtils base = SystemInstance.get().getBase();
 
         // Override with file from conf dir
-        File conf = base.getDirectory("conf");
+        final File conf = base.getDirectory("conf");
         if (conf.exists()) {
             File serviceConfig = new File(conf, serviceName + ".properties");
             if (serviceConfig.exists()) {
@@ -176,24 +177,26 @@ public abstract class ServiceManager {
                     in.close();
                 }
             } else {
-                FileOutputStream out = new FileOutputStream(serviceConfig);
-                try {
-                    String rawPropsContent = (String) serviceProperties.get(Properties.class);
-                    out.write(rawPropsContent.getBytes());
-                } finally {
-                    out.close();
+
+                if (EnvProps.extractConfigurationFiles()){
+
+                    final String rawPropsContent = (String) serviceProperties.get(Properties.class);
+                    IO.copy(IO.read(rawPropsContent), serviceConfig);
+
+                } else {
+                    serviceProperties.put("disabled", "true");
                 }
             }
         }
 
         // Override with system properties
-        String prefix = serviceName + ".";
-        Properties sysProps = new Properties(System.getProperties());
+        final String prefix = serviceName + ".";
+        final Properties sysProps = new Properties(System.getProperties());
         sysProps.putAll(SystemInstance.get().getProperties());
         for (Iterator iterator1 = sysProps.entrySet().iterator(); iterator1.hasNext();) {
-            Map.Entry entry1 = (Map.Entry) iterator1.next();
+            final Map.Entry entry1 = (Map.Entry) iterator1.next();
+            final Object value = entry1.getValue();
             String key = (String) entry1.getKey();
-            Object value = entry1.getValue();
             if (value instanceof String && key.startsWith(prefix)) {
                 key = key.replaceFirst(prefix, "");
                 serviceProperties.setProperty(key, (String) value);

Modified: openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/SimpleServiceManager.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/SimpleServiceManager.java?rev=1291185&r1=1291184&r2=1291185&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/SimpleServiceManager.java (original)
+++ openejb/trunk/openejb/server/openejb-server/src/main/java/org/apache/openejb/server/SimpleServiceManager.java Mon Feb 20 10:35:46 2012
@@ -174,6 +174,10 @@ public class SimpleServiceManager extend
             LOGGER.info("-------");
             LOGGER.info("Ready!");
         }
+
+        System.out.println("Ready!");
+        System.out.flush();
+
         if (!block) {
             return;
         }