All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.docker.client.impl.ContainerLogHandle Maven / Gradle / Ivy

The newest version!
package io.fabric8.docker.client.impl;

import io.fabric8.docker.client.DockerClientException;
import io.fabric8.docker.client.DockerStreamData;
import io.fabric8.docker.client.utils.DockerStreamPumper;
import io.fabric8.docker.dsl.EventListener;
import io.fabric8.docker.dsl.OutputErrorHandle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ContainerLogHandle implements Callback, OutputErrorHandle {

    private static final Logger LOGGER = LoggerFactory.getLogger(ContainerLogHandle.class);

    private final OutputStream out;
    private final OutputStream err;

    private final PipedInputStream pipedOutput;
    private final PipedInputStream pipedError;
    private final EventListener listener;

    private final AtomicReference response = new AtomicReference<>();
    private final AtomicReference error = new AtomicReference<>();

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();
    private DockerStreamPumper pumper;
    private final AtomicBoolean succeded = new AtomicBoolean(false);
    private final AtomicBoolean failed = new AtomicBoolean(false);

    private final CountDownLatch latch = new CountDownLatch(1);

    public ContainerLogHandle(OutputStream out, OutputStream err, PipedInputStream outputPipe,
        PipedInputStream errorPipe) {
        this(out, err, outputPipe, errorPipe, OperationSupport.NULL_LISTENER);
    }

    public ContainerLogHandle(OutputStream out, OutputStream err, PipedInputStream outputPipe, PipedInputStream errorPipe,
        EventListener listener) {

        this.out = outputStreamOrPipe(out, outputPipe);
        this.err = outputStreamOrPipe(err, errorPipe);

        this.pipedOutput = outputPipe;
        this.pipedError = errorPipe;

        this.listener = listener;
    }

    @Override
    public void onFailure(Call call, IOException e) {
        error.set(e);
        listener.onError(e);
        latch.countDown();
    }

    @Override
    public void onResponse(Call call, Response r) throws IOException {
        response.set(r);

        if (out instanceof PipedOutputStream && pipedOutput != null) {
            pipedOutput.connect((PipedOutputStream) out);
        }

        pumper =
            new DockerStreamPumper(r.body().source(),
                    new io.fabric8.docker.api.model.Callback() {
                        @Override
                        public Void call(DockerStreamData input) {
                            processStream(input);
                            writeSteam(input);
                            return null;
                        }
                    }, new Runnable() {
                @Override
                public void run() {
                    if (succeded.compareAndSet(false, true) && !failed.get()) {
                        listener.onSuccess("Done.");
                    }
                }
            }, new io.fabric8.docker.api.model.Callback() {
                @Override
                public Void call(Throwable t) {
                    if (failed.compareAndSet(false, true)) {
                        listener.onError(t);
                    }
                    return null;
                }
            });
        executorService.submit(pumper);
        latch.countDown();
    }

    private void writeSteam(DockerStreamData input) {
        if (input != null) {
            try {
                switch (input.streamType()) {
                    case STDOUT:
                    case RAW:
                        if (out != null) {
                            out.write(input.payload());
                            out.flush();
                        }
                        break;
                    case STDERR:
                        if (err != null) {
                            err.write(input.payload());
                            err.flush();
                        }
                        break;
                    default:
                        LOGGER.error("unknown stream type:" + input.streamType());
                }
            } catch (IOException e) {
                throw DockerClientException.launderThrowable(e);
            }
            LOGGER.debug(input.toString());
        }
    }

    private void processStream(DockerStreamData input) {
        if (input == null) {
            // ignore
        } else if (isFailure(input) && failed.compareAndSet(false, true)) {
            listener.onError("");
        } else {
            if (isSuccess(input) && succeded.compareAndSet(false, true)) {
                listener.onSuccess(input.toString());
            } else {
                listener.onEvent(input.toString());
            }
        }
    }

    private boolean isSuccess(DockerStreamData input) {
        return false;
    }

    private boolean isFailure(DockerStreamData input) {
        return false;
    }

    private static OutputStream outputStreamOrPipe(OutputStream stream, PipedInputStream in) {
        if (stream != null) {
            return stream;
        } else if (in != null) {
            return new PipedOutputStream();
        } else {
            return null;
        }
    }

    @Override
    public void close() throws IOException {
        pumper.close();
        executorService.shutdown();

        try {
            if (executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
            }
        } catch (Throwable t) {
            throw DockerClientException.launderThrowable(t);
        }

        Response r = response.get();
        if (r != null) {
            try {
                r.body().close();
            } catch (Throwable t) {
                LOGGER.warn("Error while closing response stream:" + t.getMessage());
            }
        }
    }

    @Override
    public InputStream getError() {
        return pipedError;
    }

    @Override
    public InputStream getOutput() {
        return pipedOutput;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy