// Path: tifoon-plugins/tifoon-docker-executor-plugin/src/main/java/com/elixlogic/tifoon/domain/model/docker/DockerImage.java
// @Data
// @NoArgsConstructor
// public class DockerImage implements Validator {
//     public static final String DEFAULT_COMMAND = "DEFAULT_COMMAND";
// 
//     @Nullable
//     private String command;
//     @Nullable
//     private String image;
// 
//     DockerImage(final String _image) {
//         command = DEFAULT_COMMAND;
//         image = _image;
//     }
// 
//     @Override
//     public void validate() {
//         Assert.hasLength(command, "command must have length");
//         Assert.hasLength(image, "image must have length");
//     }
// }
// 
// Path: tifoon-plugin-api/src/main/java/com/elixlogic/tifoon/plugin/executer/AbstractExecutorPlugin.java
// public abstract class AbstractExecutorPlugin implements ExecutorPlugin {
//     @Override
//     public PluginMetadata getMetadata() {
//         return new DefaultMetadataProvider(getClass().getName()).getMetadata();
//     }
// }
// 
// Path: tifoon-plugins/tifoon-docker-executor-plugin/src/main/java/com/elixlogic/tifoon/domain/model/docker/DockerConfiguration.java
// @ConfigurationProperties(prefix = "docker")
// @Data
// @NoArgsConstructor
// public class DockerConfiguration implements Validator {
//     @Nullable
//     private DockerImage defaultImage;
//     @Nullable
//     private List<DockerImage> customImages;
// 
//     public void setDefaultImage(@NonNull String defaultImage) {
//         this.defaultImage = new DockerImage(defaultImage);
//     }
// 
//     @Override
//     public void validate() {
//         Assert.notNull(defaultImage, "defaultImage cannot be null");
//         defaultImage.validate();
// 
//         if (customImages != null) {
//             customImages.forEach(DockerImage::validate);
//         }
//     }
// }


import com.elixlogic.tifoon.domain.model.docker.DockerImage;
import com.elixlogic.tifoon.plugin.executer.AbstractExecutorPlugin;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.PullResponseItem;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.command.ExecStartResultCallback;
import com.github.dockerjava.core.command.PullImageResultCallback;
import com.github.dockerjava.core.command.WaitContainerResultCallback;
import com.google.common.base.MoreObjects;
import com.elixlogic.tifoon.domain.model.docker.DockerConfiguration;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.SystemUtils;
import org.springframework.util.Assert;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
        return DockerClientBuilder
                .getInstance(config)
                .build();
    }

    private CreateContainerResponse createContainer(@NonNull final DockerClient _dockerClient,
                                                    @NonNull final String _dispatcher) {
        synchronized(this) {
            if (_dockerClient.listImagesCmd().withImageNameFilter(_dispatcher).exec().isEmpty()) {
                log.info("Image '" + _dispatcher + "' not found. Please wait while pulling from main repository...");

                boolean success = false;

                try {
                    success = _dockerClient.pullImageCmd(_dispatcher)
                            .exec(new PullImageResultCallback() {
                                @Override
                                public void onNext(PullResponseItem item) {
                                    //System.out.println("" + item);
                                    super.onNext(item);
                                }
                            })
                            .awaitCompletion(5, TimeUnit.MINUTES);
                } catch (InterruptedException _e) {
                    // ignore
                }

                if (!success) {
                    throw new RuntimeException("Unable to retrieve image:" + _dispatcher);
                }
// Path: tifoon-plugins/tifoon-docker-executor-plugin/src/main/java/com/elixlogic/tifoon/domain/model/docker/DockerImage.java
// @Data
// @NoArgsConstructor
// public class DockerImage implements Validator {
//     public static final String DEFAULT_COMMAND = "DEFAULT_COMMAND";
// 
//     @Nullable
//     private String command;
//     @Nullable
//     private String image;
// 
//     DockerImage(final String _image) {
//         command = DEFAULT_COMMAND;
//         image = _image;
//     }
// 
//     @Override
//     public void validate() {
//         Assert.hasLength(command, "command must have length");
//         Assert.hasLength(image, "image must have length");
//     }
// }
// 
// Path: tifoon-plugin-api/src/main/java/com/elixlogic/tifoon/plugin/executer/AbstractExecutorPlugin.java
// public abstract class AbstractExecutorPlugin implements ExecutorPlugin {
//     @Override
//     public PluginMetadata getMetadata() {
//         return new DefaultMetadataProvider(getClass().getName()).getMetadata();
//     }
// }
// 
// Path: tifoon-plugins/tifoon-docker-executor-plugin/src/main/java/com/elixlogic/tifoon/domain/model/docker/DockerConfiguration.java
// @ConfigurationProperties(prefix = "docker")
// @Data
// @NoArgsConstructor
// public class DockerConfiguration implements Validator {
//     @Nullable
//     private DockerImage defaultImage;
//     @Nullable
//     private List<DockerImage> customImages;
// 
//     public void setDefaultImage(@NonNull String defaultImage) {
//         this.defaultImage = new DockerImage(defaultImage);
//     }
// 
//     @Override
//     public void validate() {
//         Assert.notNull(defaultImage, "defaultImage cannot be null");
//         defaultImage.validate();
// 
//         if (customImages != null) {
//             customImages.forEach(DockerImage::validate);
//         }
//     }
// }


// Path: tifoon-plugins/tifoon-docker-executor-plugin/src/main/java/com/elixlogic/tifoon/plugin/DockerExecutorPlugin.java
import com.elixlogic.tifoon.domain.model.docker.DockerImage;
import com.elixlogic.tifoon.plugin.executer.AbstractExecutorPlugin;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.PullResponseItem;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.command.ExecStartResultCallback;
import com.github.dockerjava.core.command.PullImageResultCallback;
import com.github.dockerjava.core.command.WaitContainerResultCallback;
import com.google.common.base.MoreObjects;
import com.elixlogic.tifoon.domain.model.docker.DockerConfiguration;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.SystemUtils;
import org.springframework.util.Assert;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

        return DockerClientBuilder
                .getInstance(config)
                .build();
    }

    private CreateContainerResponse createContainer(@NonNull final DockerClient _dockerClient,
                                                    @NonNull final String _dispatcher) {
        synchronized(this) {
            if (_dockerClient.listImagesCmd().withImageNameFilter(_dispatcher).exec().isEmpty()) {
                log.info("Image '" + _dispatcher + "' not found. Please wait while pulling from main repository...");

                boolean success = false;

                try {
                    success = _dockerClient.pullImageCmd(_dispatcher)
                            .exec(new PullImageResultCallback() {
                                @Override
                                public void onNext(PullResponseItem item) {
                                    //System.out.println("" + item);
                                    super.onNext(item);
                                }
                            })
                            .awaitCompletion(5, TimeUnit.MINUTES);
                } catch (InterruptedException _e) {
                    // ignore
                }

                if (!success) {
                    throw new RuntimeException("Unable to retrieve image:" + _dispatcher);
                }
            } else {