diff --git a/DefaultExecHandle.java b/DockerizedExecHandle.java
old mode 100755
new mode 100644
index ac62029..b712850
--- a/DefaultExecHandle.java
+++ b/DockerizedExecHandle.java
@@ -14,10 +14,16 @@
  * limitations under the License.
  */
 
-package org.gradle.process.internal;
+package com.pedjak.gradle.plugins.dockerizedtest;
 
 import com.google.common.base.Joiner;
-import net.rubygrapefruit.platform.ProcessLauncher;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.command.CreateContainerCmd;
+import com.github.dockerjava.api.model.*;
+import com.github.dockerjava.core.command.AttachContainerResultCallback;
+import com.github.dockerjava.core.command.WaitContainerResultCallback;
+import groovy.lang.Closure;
 import org.gradle.api.logging.Logger;
 import org.gradle.api.logging.Logging;
 import org.gradle.internal.UncheckedException;
@@ -27,15 +33,15 @@ import org.gradle.internal.event.ListenerBroadcast;
 import org.gradle.internal.nativeintegration.services.NativeServices;
 import org.gradle.internal.operations.BuildOperationIdentifierPreservingRunnable;
 import org.gradle.process.ExecResult;
+import org.gradle.process.internal.*;
 import org.gradle.process.internal.shutdown.ShutdownHookActionRegister;
 import org.gradle.process.internal.streams.StreamsHandler;
 
 import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -59,9 +65,10 @@ import static java.lang.String.format;
  * <li>{@link #abort()} allowed when state is STARTED or DETACHED</li>
  * </ul>
  */
-public class DefaultExecHandle implements ExecHandle, ProcessSettings {
+public class DockerizedExecHandle implements ExecHandle, ProcessSettings
+{
 
-    private static final Logger LOGGER = Logging.getLogger(DefaultExecHandle.class);
+    private static final Logger LOGGER = Logging.getLogger(DockerizedExecHandle.class);
 
     private final String displayName;
 
@@ -86,7 +93,6 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
     private final Map<String, String> environment;
     private final StreamsHandler streamsHandler;
     private final boolean redirectErrorStream;
-    private final ProcessLauncher processLauncher;
     private final DefaultExecutorFactory executorFactory = new DefaultExecutorFactory();
     private int timeoutMillis;
     private boolean daemon;
@@ -107,7 +113,7 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
     /**
      * When not null, the runnable that is waiting
      */
-    private ExecHandleRunner execHandleRunner;
+    private DockerizedExecHandleRunner execHandleRunner;
 
     private ExecResultImpl execResult;
 
@@ -115,7 +121,9 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
 
     private final ExecHandleShutdownHookAction shutdownHookAction;
 
-    DefaultExecHandle(String displayName, File directory, String command, List<String> arguments,
+    private final DockerizedTestExtension testExtension;
+
+    public DockerizedExecHandle(DockerizedTestExtension testExtension, String displayName, File directory, String command, List<String> arguments,
                       Map<String, String> environment, StreamsHandler streamsHandler,
                       List<ExecHandleListener> listeners, boolean redirectErrorStream, int timeoutMillis, boolean daemon) {
         this.displayName = displayName;
@@ -130,8 +138,8 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
         this.lock = new ReentrantLock();
         this.stateChanged = lock.newCondition();
         this.state = ExecHandleState.INIT;
+        this.testExtension = testExtension;
         executor = executorFactory.create(format("Run %s", displayName));
-        processLauncher = NativeServices.getInstance().get(ProcessLauncher.class);
         shutdownHookAction = new ExecHandleShutdownHookAction(this);
         broadcast = new ListenerBroadcast<ExecHandleListener>(ExecHandleListener.class);
         broadcast.addAll(listeners);
@@ -243,7 +251,7 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
             }
             setState(ExecHandleState.STARTING);
 
-            execHandleRunner = new ExecHandleRunner(this, streamsHandler, processLauncher, executorFactory);
+            execHandleRunner = new DockerizedExecHandleRunner(this, streamsHandler, runContainer(), executorFactory);
             executor.execute(new BuildOperationIdentifierPreservingRunnable(execHandleRunner));
 
             while (stateIn(ExecHandleState.STARTING)) {
@@ -362,6 +370,92 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
         return timeoutMillis;
     }
 
+    private DockerClient getClient() {
+        Object clientOrClosure = testExtension.getClient();
+        if (DockerClient.class.isAssignableFrom(clientOrClosure.getClass())) {
+            return (DockerClient) clientOrClosure;
+        } else {
+            return (DockerClient) ((Closure) clientOrClosure).call();
+        }
+
+    }
+
+    private Process runContainer() {
+        try
+        {
+            DockerClient client = getClient();
+            CreateContainerCmd createCmd = client.createContainerCmd(testExtension.getImage().toString())
+                    .withTty(false)
+                    .withStdinOpen(true)
+                    .withStdInOnce(true)
+                    .withWorkingDir(directory.getAbsolutePath());
+
+            createCmd.withEnv(getEnv());
+
+            String user = testExtension.getUser();
+            if (user != null)
+                createCmd.withUser(user);
+            bindVolumes(createCmd);
+            List<String> cmdLine = new ArrayList<String>();
+            cmdLine.add(command);
+            cmdLine.addAll(arguments);
+            createCmd.withCmd(cmdLine);
+
+            invokeIfNotNull(testExtension.getBeforeContainerCreate(), createCmd, client);
+            String containerId = createCmd.exec().getId();
+            invokeIfNotNull(testExtension.getAfterContainerCreate(), containerId, client);
+
+            invokeIfNotNull(testExtension.getBeforeContainerStart(), containerId, client);
+            client.startContainerCmd(containerId).exec();
+            invokeIfNotNull(testExtension.getAfterContainerStart(), containerId, client);
+
+            if (!client.inspectContainerCmd(containerId).exec().getState().getRunning()) {
+                throw new RuntimeException("Container "+containerId+" not running!");
+            }
+
+            Process proc = new DockerizedProcess(client, containerId, testExtension.getAfterContainerStop());
+
+            return proc;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void invokeIfNotNull(Closure closure, Object... args) {
+        if (closure != null) {
+            int l = closure.getParameterTypes().length;
+            Object[] nargs;
+            if (l < args.length) {
+                nargs = new Object[l];
+                System.arraycopy(args, 0, nargs, 0, l);
+            } else {
+                nargs = args;
+            }
+            closure.call(nargs);
+        }
+    }
+    private List<String> getEnv() {
+        List<String> env = new ArrayList<String>();
+        for (Map.Entry<String, String> e: environment.entrySet()) {
+            env.add(e.getKey()+"="+e.getValue());
+        }
+        return env;
+    }
+
+    private void bindVolumes(CreateContainerCmd cmd) {
+        List<Volume> volumes = new ArrayList<Volume>();
+        List<Bind> binds = new ArrayList<Bind>();
+        for (Iterator it = testExtension.getVolumes().entrySet().iterator(); it.hasNext(); ) {
+            Map.Entry<Object, Object> e = (Map.Entry<Object, Object>) it.next();
+            Volume volume = new Volume(e.getValue().toString());
+            Bind bind = new Bind(e.getKey().toString(), volume);
+            binds.add(bind);
+            volumes.add(volume);
+        }
+        cmd.withVolumes(volumes).withBinds(binds);
+    }
+
     private static class ExecResultImpl implements ExecResult {
         private final int exitValue;
         private final ExecException failure;
@@ -378,9 +472,10 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
         }
 
         public ExecResult assertNormalExitValue() throws ExecException {
-            if (exitValue != 0) {
-                throw new ExecException(format("Process '%s' finished with non-zero exit value %d", displayName, exitValue));
-            }
+            // all exit values are ok
+//            if (exitValue != 0) {
+//                throw new ExecException(format("Process '%s' finished with non-zero exit value %d", displayName, exitValue));
+//            }
             return this;
         }
 
@@ -396,4 +491,109 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
             return "{exitValue=" + exitValue + ", failure=" + failure + "}";
         }
     }
+
+    private class DockerizedProcess extends Process {
+
+        private final DockerClient dockerClient;
+        private final String containerId;
+        private final Closure afterContainerStop;
+
+        private final PipedOutputStream stdInWriteStream = new PipedOutputStream();
+        private final PipedInputStream stdOutReadStream = new PipedInputStream();
+        private final PipedInputStream stdErrReadStream = new PipedInputStream();
+        private final PipedInputStream stdInReadStream = new PipedInputStream(stdInWriteStream);
+        private final PipedOutputStream stdOutWriteStream = new PipedOutputStream(stdOutReadStream);
+        private final PipedOutputStream stdErrWriteStream = new PipedOutputStream(stdErrReadStream);
+
+        private final CountDownLatch finished = new CountDownLatch(1);
+        private AtomicInteger exitCode = new AtomicInteger();
+        private final AttachContainerResultCallback attachContainerResultCallback = new AttachContainerResultCallback() {
+            @Override public void onNext(Frame frame)
+            {
+                try
+                {
+                    if (frame.getStreamType().equals(StreamType.STDOUT))
+                    {
+                        stdOutWriteStream.write(frame.getPayload());
+                    } else if (frame.getStreamType().equals(StreamType.STDERR)) {
+                        stdErrWriteStream.write(frame.getPayload());
+                    }
+                } catch (Exception e) {
+                    LOGGER.error("Error while writing to stream:", e);
+                }
+                super.onNext(frame);
+            }
+        };
+
+        public DockerizedProcess(final DockerClient dockerClient, final String containerId, final Closure afterContainerStop) throws Exception
+        {
+            this.dockerClient = dockerClient;
+            this.containerId = containerId;
+            this.afterContainerStop = afterContainerStop;
+            attachStreams();
+            dockerClient.waitContainerCmd(containerId).exec(new WaitContainerResultCallback() {
+                @Override public void onNext(WaitResponse waitResponse)
+                {
+                    exitCode.set(waitResponse.getStatusCode());
+                    try
+                    {
+                        attachContainerResultCallback.close();
+                        attachContainerResultCallback.awaitCompletion();
+                        stdOutWriteStream.close();
+                        stdErrWriteStream.close();
+                    } catch (Exception e) {
+                        LOGGER.debug("Error by detaching streams", e);
+                    } finally
+                    {
+                        finished.countDown();
+                        invokeIfNotNull(afterContainerStop, containerId, dockerClient);
+                    }
+
+
+                }
+            });
+        }
+
+        private void attachStreams() throws Exception {
+            dockerClient.attachContainerCmd(containerId)
+                    .withFollowStream(true)
+                    .withStdOut(true)
+                    .withStdErr(true)
+                    .withStdIn(stdInReadStream)
+                    .exec(attachContainerResultCallback);
+        }
+
+        @Override public OutputStream getOutputStream()
+        {
+            return stdInWriteStream;
+        }
+
+        @Override public InputStream getInputStream()
+        {
+            return stdOutReadStream;
+        }
+
+        @Override public InputStream getErrorStream()
+        {
+            return stdErrReadStream;
+        }
+
+        @Override public int waitFor() throws InterruptedException
+        {
+            finished.await();
+            return exitCode.get();
+        }
+
+        @Override public int exitValue()
+        {
+            if (finished.getCount() > 0) throw new IllegalThreadStateException("docker process still running");
+            return exitCode.get();
+        }
+
+        @Override public void destroy()
+        {
+            dockerClient.killContainerCmd(containerId).exec();
+        }
+    }
+
 }
