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

org.netbeans.modules.docker.api.DockerAction Maven / Gradle / Ivy

The newest version!
/*
 * 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.netbeans.modules.docker.api;

import org.netbeans.modules.docker.StreamItem;
import org.netbeans.modules.docker.ConnectionListener;
import org.netbeans.modules.docker.DockerRemoteException;
import org.netbeans.modules.docker.FolderUploader;
import org.netbeans.modules.docker.MuxedStreamResult;
import org.netbeans.modules.docker.ChunkedInputStream;
import org.netbeans.modules.docker.tls.ContextProvider;
import org.netbeans.modules.docker.IgnoreFileFilter;
import org.netbeans.modules.docker.HttpUtils;
import org.netbeans.modules.docker.DirectStreamResult;
import org.netbeans.modules.docker.Demuxer;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.ProxySelector;
import java.net.Socket;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.net.ssl.SSLContext;
import javax.swing.SwingUtilities;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.modules.docker.DockerActionAccessor;
import org.netbeans.modules.docker.DockerConfig;
import org.netbeans.modules.docker.DockerUtils;
import org.netbeans.modules.docker.Endpoint;
import org.netbeans.modules.docker.StreamResult;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketAddress;
import org.openide.filesystems.FileObject;
import org.openide.util.Pair;
import org.openide.util.Parameters;
import org.openide.util.io.NullInputStream;
import org.openide.util.io.NullOutputStream;

import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.netbeans.modules.docker.api.DockerEntityType.Container;

/**
 *
 * @author Petr Hejl
 */
public class DockerAction {

    public static final String DOCKER_FILE = "Dockerfile"; // NOI18N

    private static final Logger LOGGER = Logger.getLogger(DockerAction.class.getName());

    private static final Pattern ID_PATTERN = Pattern.compile(".*([0-9a-f]{12}([0-9a-f]{52})?).*");

    private static final Pattern PORT_PATTERN = Pattern.compile("^(\\d+)/(tcp|udp)$");

    private static final Set START_STOP_CONTAINER_CODES = new HashSet<>();

    private static final Set REMOVE_CONTAINER_CODES = new HashSet<>();

    private static final Set REMOVE_IMAGE_CODES = new HashSet<>();

    private static final Pair ACCEPT_JSON_HEADER = Pair.of("Accept", "application/json");

    static {
        DockerActionAccessor.setDefault(new DockerActionAccessor() {
            @Override
            public void events(DockerAction action, Long since, DockerEvent.Listener listener, ConnectionListener connectionListener) throws DockerException {
                action.events(since, listener, connectionListener);
            }
        });

        Collections.addAll(START_STOP_CONTAINER_CODES, HttpURLConnection.HTTP_NO_CONTENT, HttpURLConnection.HTTP_NOT_MODIFIED);
        Collections.addAll(REMOVE_CONTAINER_CODES, HttpURLConnection.HTTP_NO_CONTENT, HttpURLConnection.HTTP_NOT_FOUND);
        Collections.addAll(REMOVE_IMAGE_CODES, HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_NOT_FOUND);
    }

    private final DockerInstance instance;

    private final boolean emitEvents;

    public DockerAction(DockerInstance instance) {
        this(instance, true);
    }

    // not needed in the api for now
    private DockerAction(DockerInstance instance, boolean emitEvents) {
        this.instance = instance;
        this.emitEvents = emitEvents;
    }

    public List getImages() {
        try {
            JSONArray value = (JSONArray) doGetRequest("/images/json",
                    Collections.singleton(HttpURLConnection.HTTP_OK));
            List ret = new ArrayList<>(value.size());
            for (Object o : value) {
                JSONObject json = (JSONObject) o;
                JSONArray repoTags = (JSONArray) json.get("RepoTags");
                String id = (String) json.get("Id");
                long created = (long) json.getOrDefault("Created", 0L);
                long size = (long) json.getOrDefault("Size", 0L);
                long virtualSize = (long) json.getOrDefault("VirtualSize", size);
                ret.add(new DockerImage(instance, repoTags, id, created, size, virtualSize));
            }
            return ret;
        } catch (DockerException ex) {
            LOGGER.log(Level.INFO, null, ex);
        }
        return Collections.emptyList();
    }

    public List getContainers() {
        try {
            JSONArray value = (JSONArray) doGetRequest("/containers/json?all=1",
                    Collections.singleton(HttpURLConnection.HTTP_OK));
            List ret = new ArrayList<>(value.size());
            for (Object o : value) {
                JSONObject json = (JSONObject) o;
                String id = (String) json.get("Id");
                String image = (String) json.get("Image");
                String name = null;
                JSONArray names = (JSONArray) json.get("Names");
                if (names != null && !names.isEmpty()) {
                    name = (String) names.get(0);
                }
                DockerContainer.Status status = DockerUtils.getContainerStatus((String) json.get("Status"));
                ret.add(new DockerContainer(instance, id, image, name, status));
            }
            return ret;
        } catch (DockerException ex) {
            LOGGER.log(Level.INFO, null, ex);
        }
        return Collections.emptyList();
    }

    public List search(String searchTerm) {
        // the api does not allow this TAG and DIGEST separator characters
        if (searchTerm.contains(":") || searchTerm.contains("@")) { // NOI18N
            return Collections.emptyList();
        }

        try {
            JSONArray value = (JSONArray) doGetRequest(
                    "/images/search?term=" + HttpUtils.encodeParameter(searchTerm),
                    Collections.singleton(HttpURLConnection.HTTP_OK));
            List ret = new ArrayList<>(value.size());
            for (Object o : value) {
                JSONObject json = (JSONObject) o;
                String name = (String) json.get("name");
                String description = (String) json.get("description");
                long stars = ((Number) getOrDefault(json, "star_count", 0)).longValue();
                boolean official = (boolean) getOrDefault(json, "is_official", false);
                boolean automated = (boolean) getOrDefault(json, "is_automated", false);
                ret.add(new DockerRegistryImage(name, description, stars, official, automated));
            }
            return ret;
        } catch (DockerException | UnsupportedEncodingException ex) {
            LOGGER.log(Level.INFO, null, ex);
        }
        return Collections.emptyList();
    }

    public DockerImage commit(DockerContainer container, String repository, String tag,
            String author, String message, boolean pause) throws DockerException {

        if (repository == null && tag != null) {
            throw new IllegalArgumentException("Repository can't be empty when using tag");
        }

        try {
            StringBuilder action = new StringBuilder("/commit");
            action.append("?");
            action.append("container=").append(container.getId());
            if (repository != null) {
                action.append("&repo=").append(HttpUtils.encodeParameter(repository));
                if (tag != null) {
                    action.append("&tag=").append(HttpUtils.encodeParameter(tag));
                }
            }
            if (author != null) {
                action.append("&author=").append(HttpUtils.encodeParameter(author));
            }
            if (message != null) {
                action.append("&comment=").append(HttpUtils.encodeParameter(message));
            }
            if (!pause) {
                action.append("&pause=0");
            }

            JSONObject value = (JSONObject) doPostRequest(action.toString(),
                    true, Collections.singleton(HttpURLConnection.HTTP_CREATED));

            String id = (String) value.get("Id");

            long time = System.currentTimeMillis() / 1000;
            // XXX we send it as older API does not have the commit event
            if (emitEvents) {
                instance.getEventBus().sendEvent(
                        new DockerEvent(instance, DockerEvent.Status.COMMIT,
                                id, container.getId(), time));
            }

            // FIXME image size and time parameters
            return new DockerImage(instance, Collections.singletonList(DockerUtils.getTag(repository, tag)),
                    (String) value.get("Id"), time, 0, 0);

        } catch (UnsupportedEncodingException ex) {
            throw new DockerException(ex);
        }
    }

    public void rename(DockerContainer container, String name) throws DockerException {
        Parameters.notNull("name", name);

        try {
            doPostRequest("/containers/" + container.getId() + "/rename?name=" + HttpUtils.encodeParameter(name),
                    false, Collections.singleton(HttpURLConnection.HTTP_NO_CONTENT));

            long time = System.currentTimeMillis() / 1000;
            // XXX we send it as older API does not have the commit event
            if (emitEvents) {
                instance.getEventBus().sendEvent(
                        new DockerEvent(instance, DockerEvent.Status.RENAME,
                                container.getId(), container.getId(), time));
            }
        } catch (UnsupportedEncodingException ex) {
            throw new DockerException(ex);
        }
    }

    public DockerTag tag(DockerTag source, String repository, String tag, boolean force) throws DockerException {
        if (repository == null) {
            throw new IllegalArgumentException("Repository can't be empty");
        }

        StringBuilder action = new StringBuilder("/images/");
        action.append(source.getId());
        action.append("/tag");
        action.append("?");
        action.append("repo=").append(repository);
        if (force) {
            action.append("&force=1");
        }
        if (tag != null) {
            action.append("&tag=").append(tag);
        }

        doPostRequest(action.toString(),
                false, Collections.singleton(HttpURLConnection.HTTP_CREATED));

        String tagResult = DockerUtils.getTag(repository, tag);
        long time = System.currentTimeMillis() / 1000;
        // XXX we send it as older API does not have the commit event
        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.TAG,
                            source.getId(), tagResult, time));
        }

        return new DockerTag(source.getImage(), tagResult);
    }

    public JSONObject getRawDetails(DockerEntityType entityType, String containerId) throws DockerException {
        JSONObject value = (JSONObject) doGetRequest(entityType.getUrlPath() + containerId + "/json",
                Collections.singleton(HttpURLConnection.HTTP_OK));
        return value;
    }
    
    public DockerContainerDetail getDetail(DockerContainer container) throws DockerException {
        JSONObject value = getRawDetails(DockerEntityType.Container, container.getId());
        String name = (String) value.get("Name");
        DockerContainer.Status status = DockerContainer.Status.STOPPED;
        JSONObject state = (JSONObject) value.get("State");
        if (state != null) {
            boolean paused = (Boolean) getOrDefault(state, "Paused", false);
            if (paused) {
                status = DockerContainer.Status.PAUSED;
            } else {
                boolean running = (Boolean) getOrDefault(state, "Running", false);
                if (running) {
                    status = DockerContainer.Status.RUNNING;
                }
            }
        }

        boolean tty = false;
        boolean stdin = false;
        JSONObject config = (JSONObject) value.get("Config");
        if (config != null) {
            tty = (boolean) getOrDefault(config, "Tty", false);
            stdin = (boolean) getOrDefault(config, "OpenStdin", false);
        }
        JSONObject ports = (JSONObject) ((JSONObject) value.get("NetworkSettings")).get("Ports");
        if (ports == null || ports.isEmpty()) {
            return new DockerContainerDetail(name, status, stdin, tty);
        } else {
            List portMapping = new ArrayList<>();
            for (String containerPortData : (Set) ports.keySet()) {
                JSONArray hostPortsArray = (JSONArray) ports.get(containerPortData);
                if (hostPortsArray != null && !hostPortsArray.isEmpty()) {
                    Matcher m = PORT_PATTERN.matcher(containerPortData);
                    if (m.matches()) {
                        int containerPort = Integer.parseInt(m.group(1));
                        String type = m.group(2).toUpperCase(Locale.ENGLISH);
                        int hostPort = Integer.parseInt((String) ((JSONObject) hostPortsArray.get(0)).get("HostPort"));
                        String hostIp = (String) ((JSONObject) hostPortsArray.get(0)).get("HostIp");
                        portMapping.add(new PortMapping(ExposedPort.Type.valueOf(type), containerPort, hostPort, hostIp));
                    } else {
                        LOGGER.log(Level.FINE, "Unparsable port: {0}", containerPortData);
                    }
                }
            }
            return new DockerContainerDetail(name, status, stdin, tty, portMapping);
        }
    }

    public DockerImageDetail getDetail(DockerImage image) throws DockerException {
        JSONObject value = (JSONObject) doGetRequest("/images/" + image.getId() + "/json",
                Collections.singleton(HttpURLConnection.HTTP_OK));
        List ports = new LinkedList<>();
        JSONObject config = (JSONObject) value.get("Config");
        if (config != null) {
            JSONObject portsObject = (JSONObject) config.get("ExposedPorts");
            if (portsObject != null) {
                for (Object k : portsObject.keySet()) {
                    String portStr = (String) k;
                    Matcher m = PORT_PATTERN.matcher(portStr);
                    if (m.matches()) {
                        int port = Integer.parseInt(m.group(1));
                        ExposedPort.Type type = ExposedPort.Type.valueOf(m.group(2).toUpperCase(Locale.ENGLISH));
                        ports.add(new ExposedPort(port, type));
                    } else {
                        LOGGER.log(Level.FINE, "Unparsable port: {0}", portStr);
                    }
                }
            }
        }
        return new DockerImageDetail(ports);
    }

    public DockerfileDetail getDetail(FileObject dockerfile) throws IOException {
        // Each ARG line looks like:
        // "(\w)*ARG(\w)*key=val(\w)*"

        // Filter this lines and remove ARG from the beginning
        List argLines = dockerfile.asLines().stream()
                .filter((line) -> line.trim().matches("^(?i)arg(.*)$")) // NOI18N
                .map((argLine) -> argLine.trim().replaceFirst("^(?i)arg", "").trim()) // NOI18N
                .collect(Collectors.toList());

        // Now each line looks like: "key=val"
        Map pairs = new HashMap<>();
        for (String line : argLines) {
            String[] split = line.split("=", 2); // NOI18N
            pairs.put(split[0], split.length == 2 ? split[1] : ""); //NOI18N
        }

        return new DockerfileDetail(pairs);
    }

    public void start(DockerContainer container) throws DockerException {
        doPostRequest("/containers/" + container.getId() + "/start", false, START_STOP_CONTAINER_CODES);

        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.START,
                            container.getId(), container.getImage(), System.currentTimeMillis() / 1000));
        }
    }

    public void stop(DockerContainer container) throws DockerException {
        doPostRequest("/containers/" + container.getId() + "/stop", false, START_STOP_CONTAINER_CODES);

        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.DIE,
                            container.getId(), container.getImage(), System.currentTimeMillis() / 1000));
        }
    }

    public void pause(DockerContainer container) throws DockerException {
        doPostRequest("/containers/" + container.getId() + "/pause", false,
                Collections.singleton(HttpURLConnection.HTTP_NO_CONTENT));

        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.PAUSE,
                            container.getId(), container.getImage(), System.currentTimeMillis() / 1000));
        }
    }

    public void unpause(DockerContainer container) throws DockerException {
        doPostRequest("/containers/" + container.getId() + "/unpause", false,
                Collections.singleton(HttpURLConnection.HTTP_NO_CONTENT));

        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.UNPAUSE,
                            container.getId(), container.getImage(), System.currentTimeMillis() / 1000));
        }
    }

    public void remove(DockerTag tag) throws DockerException {
        String id = getImage(tag);
        doDeleteRequest("/images/" + id, true, REMOVE_IMAGE_CODES);

        // XXX to be precise we should emit DELETE event if we
        // delete the last image, but for our purpose this is enough
        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.UNTAG,
                            tag.getId(), null, System.currentTimeMillis() / 1000));
        }
    }

    public void remove(DockerContainer container) throws DockerException {
        doDeleteRequest("/containers/" + container.getId(), false,
                REMOVE_CONTAINER_CODES);

        if (emitEvents) {
            instance.getEventBus().sendEvent(
                    new DockerEvent(instance, DockerEvent.Status.DESTROY,
                            container.getId(), container.getImage(), System.currentTimeMillis() / 1000));
        }
    }

    public void resizeTerminal(DockerContainer container, int rows, int columns) throws DockerException {
        // formally there should be restart so changes take place
        doPostRequest("/containers/" + container.getId() + "/resize?h=" + rows + "&w=" + columns,
                false, Collections.singleton(HttpURLConnection.HTTP_OK));
    }

    // this call is BLOCKING
    public ActionStreamResult attach(DockerContainer container, boolean stdin, boolean logs) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        DockerContainerDetail info = DockerAction.this.getDetail(container);
        Endpoint s = null;
        try {
            s = createEndpoint();

            OutputStream os = s.getOutputStream();
            os.write(("POST /containers/" + container.getId()
                    + "/attach?logs=" + (logs ? 1 : 0)
                    + "&stream=1&stdout=1&stdin=" + (stdin ? 1 : 0)
                    + "&stderr=1 HTTP/1.1\r\n").getBytes(ISO_8859_1));
            HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(),
                    getHostHeader(),
                    Pair.of("Connection", "Upgrade"),
                    Pair.of("Upgrade", "tcp"));
            os.write("\r\n".getBytes(ISO_8859_1));
            os.flush();

            InputStream is = s.getInputStream();
            HttpUtils.Response response = HttpUtils.readResponse(is);
            int responseCode = response.getCode();
            if (responseCode != 101 && responseCode != HttpURLConnection.HTTP_OK) {
                String error = HttpUtils.readContent(is, response);
                throw new DockerRemoteException(responseCode, error != null ? error : response.getMessage());
            }

            if (emitEvents) {
                instance.getEventBus().sendEvent(
                        new DockerEvent(instance, DockerEvent.Status.ATTACH,
                                container.getId(), container.getImage(), System.currentTimeMillis() / 1000));
            }

            Charset ch = HttpUtils.getCharset(response);
            Integer length = HttpUtils.getLength(response.getHeaders());
            if (length != null && length <= 0) {
                closeEndpoint(s);
                return new ActionStreamResult(new EmptyStreamResult(info.isTty()));
            }
            is = HttpUtils.getResponseStream(is, response, true);

            if (info.isTty()) {
                return new ActionStreamResult(new DirectStreamResult(s, ch, is));
            } else {
                return new ActionStreamResult(new MuxedStreamResult(s, ch, is));
            }
        } catch (MalformedURLException e) {
            closeEndpoint(s);
            throw new DockerException(e);
        } catch (IOException e) {
            closeEndpoint(s);
            throw new DockerException(e);
        } catch (DockerException e) {
            closeEndpoint(s);
            throw e;
        }
    }

    // this call is BLOCKING
    public void pull(String imageName, StatusEvent.Listener listener) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        try {
            DockerName parsed = DockerName.parse(imageName);
            Endpoint s = createEndpoint();
            try {
                OutputStream os = s.getOutputStream();
                os.write(("POST /images/create?fromImage="
                        + HttpUtils.encodeParameter(imageName) + " HTTP/1.1\r\n").getBytes(ISO_8859_1));
                Pair authHeader = null;
                JSONObject auth = createAuthObject(CredentialsManager.getDefault().getCredentials(parsed.getRegistry()));
                authHeader = Pair.of("X-Registry-Auth", HttpUtils.encodeBase64(auth.toJSONString()));
                HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(),
                        getHostHeader(), ACCEPT_JSON_HEADER, authHeader);
                os.write(("\r\n").getBytes(ISO_8859_1));
                os.flush();

                InputStream is = s.getInputStream();
                HttpUtils.Response response = HttpUtils.readResponse(is);
                int responseCode = response.getCode();

                is = HttpUtils.getResponseStream(is, response, false);

                if (responseCode != HttpURLConnection.HTTP_OK) {
                    String error = HttpUtils.readContent(is, response);
                    throw codeToException(responseCode,
                            error != null ? error : response.getMessage());
                }

                String authFailure = null;
                JSONParser parser = new JSONParser();
                try (InputStreamReader r = new InputStreamReader(is, HttpUtils.getCharset(response))) {
                    String line;
                    while ((line = readEventObject(r)) != null) {
                        JSONObject o = (JSONObject) parser.parse(line);
                        StatusEvent e = parseStatusEvent(o);
                        if (e != null) {
                            if (authFailure == null) {
                                authFailure = getAuthenticationFailure(e);
                            }
                            listener.onEvent(e);
                        }
                        parser.reset();
                    }
                } catch (ParseException ex) {
                    throw new DockerException(ex);
                }

                if (authFailure != null) {
                    throw new DockerAuthenticationException(authFailure);
                }
            } finally {
                closeEndpoint(s);
            }
        } catch (MalformedURLException e) {
            throw new DockerException(e);
        } catch (IOException e) {
            throw new DockerException(e);
        }
    }

    // this call is BLOCKING
    public void push(DockerTag tag, StatusEvent.Listener listener) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        try {
            String name = tag.getTag();
            DockerName parsed = DockerName.parse(name);
            String tagString = parsed.getTag();
            StringBuilder action = new StringBuilder();
            action.append("/images/");
            if (tagString == null) {
                action.append(name);
            } else {
                action.append(name.substring(0, name.length() - tagString.length() - 1));
            }
            action.append("/push");
            if (tagString != null) {
                action.append("?tag=").append(HttpUtils.encodeParameter(tagString));
            }

            Endpoint s = createEndpoint();
            try {
                OutputStream os = s.getOutputStream();
                os.write(("POST " + action.toString() + " HTTP/1.1\r\n").getBytes(ISO_8859_1));
                Pair authHeader = null;
                JSONObject auth = createAuthObject(CredentialsManager.getDefault().getCredentials(parsed.getRegistry()));
                authHeader = Pair.of("X-Registry-Auth", HttpUtils.encodeBase64(auth.toJSONString()));
                HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(),
                        getHostHeader(), ACCEPT_JSON_HEADER, authHeader);
                os.write(("\r\n").getBytes(ISO_8859_1));
                os.flush();

                InputStream is = s.getInputStream();
                HttpUtils.Response response = HttpUtils.readResponse(is);
                int responseCode = response.getCode();

                is = HttpUtils.getResponseStream(is, response, false);

                if (responseCode != HttpURLConnection.HTTP_OK) {
                    String error = HttpUtils.readContent(is, response);
                    throw codeToException(responseCode,
                            error != null ? error : response.getMessage());
                }

                String authFailure = null;
                JSONParser parser = new JSONParser();
                try (InputStreamReader r = new InputStreamReader(is, HttpUtils.getCharset(response))) {
                    String line;
                    while ((line = readEventObject(r)) != null) {
                        JSONObject o = (JSONObject) parser.parse(line);
                        StatusEvent e = parseStatusEvent(o);
                        if (e != null) {
                            if (authFailure == null) {
                                authFailure = getAuthenticationFailure(e);
                            }
                            listener.onEvent(e);
                        }
                        parser.reset();
                    }
                } catch (ParseException ex) {
                    throw new DockerException(ex);
                }

                if (authFailure != null) {
                    throw new DockerAuthenticationException(authFailure);
                }
            } finally {
                closeEndpoint(s);
            }
        } catch (MalformedURLException e) {
            throw new DockerException(e);
        } catch (IOException e) {
            throw new DockerException(e);
        }
    }

    public FutureTask createBuildTask(@NonNull FileObject buildContext, @NullAllowed FileObject dockerfile,
            @NullAllowed Map buildargs,
            String repository, String tag, boolean pull, boolean noCache,
            final BuildEvent.Listener buildListener, final StatusEvent.Listener statusListener) {

        final CancelHandler handler = new CancelHandler();
        Callable callable = new Callable() {

            @Override
            public DockerImage call() throws Exception {
                assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

                if (!buildContext.isFolder()) {
                    throw new IllegalArgumentException("Build context has to be a directory");
                }
                if (dockerfile != null && !dockerfile.isData()) {
                    throw new IllegalArgumentException("Dockerfile has to be a file");
                }
                if (repository == null && tag != null) {
                    throw new IllegalArgumentException("Repository can't be empty when using tag");
                }

                String dockerfileName = null;
                if (dockerfile != null) {
                    dockerfileName = dockerfile.getName();
                }

                Endpoint s = null;
                try {
                    s = createEndpoint();
                    synchronized (handler) {
                        if (handler.isCancelled()) {
                            return null;
                        }
                        handler.setEndpoint(s);
                    }

                    StringBuilder request = new StringBuilder();
                    request.append("POST /build?");
                    request.append("pull=").append(pull ? 1 : 0);
                    request.append("&nocache=").append(noCache ? 1 : 0);
                    if (dockerfileName != null) {
                        request.append("&dockerfile=").append(HttpUtils.encodeParameter(dockerfileName));
                    }
                    if (repository != null) {
                        request.append("&t=").append(HttpUtils.encodeParameter(repository));
                        if (tag != null) {
                            request.append(":").append(tag);
                        }
                    }
                    if (buildargs != null && !buildargs.isEmpty()) {
                        request.append("&buildargs=").append((new JSONObject(buildargs)).toString());
                    }
                    request.append(" HTTP/1.1\r\n");

                    JSONObject registryConfig = new JSONObject();
                    JSONObject configs = new JSONObject();
                    registryConfig.put("configs", configs);
                    for (Credentials c : DockerConfig.getDefault().getAllCredentials()) {
                        configs.put(c.getRegistry(), createAuthObject(c));
                    }

                    Pair configHeader = null;
                    if (!configs.isEmpty()) {
                        configHeader = Pair.of("X-Registry-Config", HttpUtils.encodeBase64(registryConfig.toJSONString()));
                    }
                    HttpUtils.configureHeaders(request, DockerConfig.getDefault().getHttpHeaders(),
                            configHeader,
                            getHostHeader(),
                            Pair.of("Transfer-Encoding", "chunked"),
                            Pair.of("Content-Type", "application/tar"),
                            Pair.of("Content-Encoding", "gzip"));
                    request.append("\r\n");

                    OutputStream os = s.getOutputStream();
                    os.write(request.toString().getBytes(ISO_8859_1));
                    os.flush();

                    buildListener.onEvent(new BuildEvent(instance, request.toString(), false, null, false));

                    // FIXME should we allow \ as separator as that would be formally
                    // separator on windows without possibility to escape anything
                    // If we would allow that we have to use File comparison
                    Future task = new FolderUploader(instance, os).upload(buildContext,
                            new IgnoreFileFilter(buildContext, dockerfile, '/'), new FolderUploader.Listener() {
                        @Override
                        public void onUpload(String path) {
                            buildListener.onEvent(new BuildEvent(instance, path, false, null, true));
                        }
                    });

                    InputStream is = s.getInputStream();
                    HttpUtils.Response response = HttpUtils.readResponse(is);
                    int responseCode = response.getCode();
                    if (responseCode != HttpURLConnection.HTTP_OK) {
                        task.cancel(true);
                        String error = HttpUtils.readContent(is, response);
                        throw codeToException(responseCode,
                                error != null ? error : response.getMessage());
                    }

                    try {
                        if (task.isDone()) {
                            task.get();
                        } else {
                            LOGGER.log(Level.INFO, "Server responded OK yet upload has not finished");
                            task.cancel(true);
                        }
                    } catch (InterruptedException ex) {
                        LOGGER.log(Level.INFO, null, ex);
                        Thread.currentThread().interrupt();
                    } catch (ExecutionException ex) {
                        throw new DockerException(ex.getCause());
                    }

                    is = HttpUtils.getResponseStream(is, response, false);

                    JSONParser parser = new JSONParser();
                    try (InputStreamReader r = new InputStreamReader(is, HttpUtils.getCharset(response))) {
                        String line;
                        String stream = null;
                        while ((line = readEventObject(r)) != null) {
                            JSONObject o = (JSONObject) parser.parse(line);
                            stream = (String) o.get("stream");
                            if (stream != null) {
                                buildListener.onEvent(new BuildEvent(instance, stream.trim(), false, null, false));
                            } else if (o.containsKey("status")) {
                                StatusEvent e = parseStatusEvent(o);
                                if (e != null) {
                                    statusListener.onEvent(e);
                                }
                            } else {
                                String error = (String) o.get("error");
                                if (error != null) {
                                    BuildEvent.Error detail = null;
                                    JSONObject detailObj = (JSONObject) o.get("errorDetail");
                                    if (detailObj != null) {
                                        long code = ((Number) getOrDefault(detailObj, "code", 0)).longValue();
                                        String mesage = (String) detailObj.get("message");
                                        detail = new BuildEvent.Error(code, mesage);
                                    }
                                    buildListener.onEvent(new BuildEvent(instance, error, true, detail, false));
                                } else {
                                    LOGGER.log(Level.INFO, "Unknown event {0}", o);
                                }
                            }
                            parser.reset();
                        }

                        if (stream != null) {
                            Matcher m = ID_PATTERN.matcher(stream.trim());
                            if (m.matches()) {
                                // the docker itself does not emit any event for built image
                                // we assume the last stream contains the built image id
                                // FIXME as there is no BUILD event we use PULL event
                                long time = System.currentTimeMillis() / 1000;
                                if (emitEvents) {
                                    instance.getEventBus().sendEvent(
                                            new DockerEvent(instance, DockerEvent.Status.PULL,
                                                    m.group(1), null, time));
                                }
                                // FIXME image size and time parameters
                                return new DockerImage(instance, Collections.singletonList(DockerUtils.getTag(repository, tag)),
                                        m.group(1), time, 0, 0);
                            }
                        }
                    } catch (ParseException ex) {
                        throw new DockerException(ex);
                    }
                    return null;
                } catch (MalformedURLException e) {
                    closeEndpoint(s);
                    throw new DockerException(e);
                } catch (IOException e) {
                    closeEndpoint(s);
                    if (!handler.isCancelled()) {
                        throw new DockerException(e);
                    }
                    return null;
                } catch (DockerException e) {
                    closeEndpoint(s);
                    throw e;
                }
            }
        };

        return new FutureTask(callable) {

            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                super.cancel(false);
                if (mayInterruptIfRunning) {
                    handler.cancel();
                }
                return true;
            }
        };
    }

    // this call is BLOCKING
    public ActionChunkedResult logs(DockerContainer container) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        DockerContainerDetail info = getDetail(container);
        Endpoint s = null;
        try {
            s = createEndpoint();

            OutputStream os = s.getOutputStream();
            os.write(("GET /containers/" + container.getId() + "/logs?stderr=1&stdout=1×tamps=1&follow=1 HTTP/1.1\r\n").getBytes(ISO_8859_1));
            HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(), getHostHeader());
            os.write("\r\n".getBytes(ISO_8859_1));
            os.flush();

            InputStream is = s.getInputStream();
            HttpUtils.Response response = HttpUtils.readResponse(is);
            int responseCode = response.getCode();
            if (responseCode != 101 && responseCode != HttpURLConnection.HTTP_OK) {
                String error = HttpUtils.readContent(is, response);
                throw new DockerRemoteException(responseCode,
                        error != null ? error : response.getMessage());
            }

            is = HttpUtils.getResponseStream(is, response, true);

            StreamItem.Fetcher fetcher;
            Integer length = HttpUtils.getLength(response.getHeaders());
            // if there was no log it may return just standard reply with content length 0
            if (length != null && length == 0) {
                assert !(is instanceof ChunkedInputStream);
                LOGGER.log(Level.INFO, "Empty logs");
                fetcher = new StreamItem.Fetcher() {
                    @Override
                    public StreamItem fetch() {
                        return null;
                    }
                };
            } else if (info.isTty()) {
                fetcher = new DirectFetcher(is);
            } else {
                fetcher = new Demuxer(is);
            }
            return new ActionChunkedResult(s, fetcher, HttpUtils.getCharset(response));
        } catch (MalformedURLException e) {
            closeEndpoint(s);
            throw new DockerException(e);
        } catch (IOException e) {
            closeEndpoint(s);
            throw new DockerException(e);
        } catch (DockerException e) {
            closeEndpoint(s);
            throw e;
        }
    }

    // this call is BLOCKING
    public Pair run(String name, JSONObject configuration) throws DockerException {
        Endpoint s = null;
        try {
            s = createEndpoint();

            byte[] data = configuration.toJSONString().getBytes(UTF_8);
            Map defaultHeaders = DockerConfig.getDefault().getHttpHeaders();

            OutputStream os = s.getOutputStream();
            os.write(("POST " + (name != null ? "/containers/create?name=" + HttpUtils.encodeParameter(name) : "/containers/create") + " HTTP/1.1\r\n").getBytes(ISO_8859_1));
            HttpUtils.configureHeaders(os, defaultHeaders,
                    getHostHeader(),
                    Pair.of("Content-Type", "application/json"),
                    Pair.of("Content-Length", Integer.toString(data.length)));
            os.write("\r\n".getBytes(ISO_8859_1));
            os.write(data);
            os.flush();

            InputStream is = s.getInputStream();
            HttpUtils.Response response = HttpUtils.readResponse(is);
            if (response.getCode() != HttpURLConnection.HTTP_CREATED) {
                String error = HttpUtils.readContent(is, response);
                throw new DockerRemoteException(response.getCode(),
                        error != null ? error : response.getMessage());
            }

            // we send a second request to the stream later
            InputStream nis = HttpUtils.getResponseStream(is, response, false);

            JSONObject value;
            try {
                JSONParser parser = new JSONParser();
                value = (JSONObject) parser.parse(HttpUtils.readContent(nis, response));
            } catch (ParseException ex) {
                throw new DockerException(ex);
            }

            String id = (String) value.get("Id");
            DockerContainer container = new DockerContainer(
                    instance,
                    id,
                    (String) configuration.get("Image"),
                    "/" + name,
                    DockerContainer.Status.STOPPED);
            ActionStreamResult r = attach(container, true, true);

            os.write(("POST /containers/" + id + "/start HTTP/1.1\r\n").getBytes(ISO_8859_1));
            HttpUtils.configureHeaders(os, defaultHeaders, getHostHeader());
            os.write("\r\n".getBytes(ISO_8859_1));
            os.flush();

            response = HttpUtils.readResponse(is);
            if (response.getCode() != HttpURLConnection.HTTP_NO_CONTENT) {
                String error = HttpUtils.readContent(is, response);
                throw codeToException(response.getCode(),
                        error != null ? error : response.getMessage());
            }

            return Pair.of(container, r);
        } catch (MalformedURLException e) {
            closeEndpoint(s);
            throw new DockerException(e);
        } catch (IOException e) {
            closeEndpoint(s);
            throw new DockerException(e);
        } catch (DockerException e) {
            closeEndpoint(s);
            throw e;
        }
    }

    public boolean pingWithExceptions() throws Exception {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";
        Endpoint s = createEndpoint();
        try {
            OutputStream os = s.getOutputStream();
            // FIXME should we use default headers ?
            os.write(("GET /_ping HTTP/1.1\r\n"
                    + "Host: " + getHostHeader().second() + "\r\n\r\n").getBytes(ISO_8859_1));
            os.flush();

            InputStream is = s.getInputStream();
            HttpUtils.Response response = HttpUtils.readResponse(is);
            return response.getCode() == HttpURLConnection.HTTP_OK;
        } finally {
            closeEndpoint(s);
        }
    }
    
    public boolean ping() {      
        try {
            return pingWithExceptions();
        } catch (MalformedURLException ex) {
            LOGGER.log(Level.INFO, null, ex);
        } catch (Exception ex) {
            LOGGER.log(Level.FINE, null, ex);
        }
        return false;
    }

    // this call is BLOCKING
    private void events(Long since, DockerEvent.Listener listener, ConnectionListener connectionListener) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        try {
            Endpoint s = createEndpoint();
            try {
                OutputStream os = s.getOutputStream();
                os.write(("GET " + (since != null ? "/events?since=" + since : "/events") + " HTTP/1.1\r\n"
                        + "Host: " + getHostHeader().second() + "\r\n"
                        + "Accept: application/json\r\n\r\n").getBytes(ISO_8859_1));
                os.flush();

                InputStream is = s.getInputStream();
                HttpUtils.Response response = HttpUtils.readResponse(is);
                int responseCode = response.getCode();

                if (responseCode != HttpURLConnection.HTTP_OK) {
                    String error = HttpUtils.readContent(is, response);
                    throw new DockerRemoteException(responseCode,
                            error != null ? error : response.getMessage());
                }

                is = HttpUtils.getResponseStream(is, response, false);

                if (connectionListener != null) {
                    connectionListener.onConnect(s);
                }

                JSONParser parser = new JSONParser();
                try (InputStreamReader r = new InputStreamReader(is, HttpUtils.getCharset(response))) {
                    String line;
                    while ((line = readEventObject(r)) != null) {
                        JSONObject o = (JSONObject) parser.parse(line);
                        DockerEvent.Status status = DockerEvent.Status.parse((String) o.get("status"));
                        String id = (String) o.get("id");
                        String from = (String) o.get("from");
                        long time = (Long) o.get("time");
                        if (status == null) {
                            LOGGER.log(Level.INFO, "Unknown event {0}", o);
                        } else {
                            listener.onEvent(new DockerEvent(instance, status, id, from, time));
                        }
                        parser.reset();
                    }
                } catch (ParseException ex) {
                    throw new DockerException(ex);
                } finally {
                    if (connectionListener != null) {
                        connectionListener.onDisconnect();
                    }
                }
            } finally {
                closeEndpoint(s);
            }
        } catch (MalformedURLException e) {
            throw new DockerException(e);
        } catch (IOException e) {
            throw new DockerException(e);
        }
    }

    private Object doGetRequest(@NonNull String action, Set okCodes) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        try {
            Endpoint s = createEndpoint();
            try {
                OutputStream os = s.getOutputStream();
                os.write(("GET " + action + " HTTP/1.1\r\n").getBytes(ISO_8859_1));
                HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(),
                        getHostHeader(), ACCEPT_JSON_HEADER);
                os.write(("\r\n").getBytes(ISO_8859_1));
                os.flush();

                InputStream is = s.getInputStream();
                HttpUtils.Response response = HttpUtils.readResponse(is);
                int responseCode = response.getCode();

                if (!okCodes.contains(responseCode)) {
                    String error = HttpUtils.readContent(is, response);
                    throw codeToException(responseCode,
                            error != null ? error : response.getMessage());
                }

                is = HttpUtils.getResponseStream(is, response, false);

                try (BufferedReader br = new BufferedReader(new InputStreamReader(
                        is, HttpUtils.getCharset(response)))) {
                    JSONParser parser = new JSONParser();
                    return parser.parse(br);
                } catch (ParseException ex) {
                    throw new DockerException(ex);
                }
            } finally {
                closeEndpoint(s);
            }
        } catch (MalformedURLException e) {
            throw new DockerException(e);
        } catch (IOException e) {
            throw new DockerException(e);
        }
    }

    private Object doPostRequest(@NonNull String action, boolean output, Set okCodes) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        try {
            Endpoint s = createEndpoint();
            try {
                OutputStream os = s.getOutputStream();
                os.write(("POST " + action + " HTTP/1.1\r\n").getBytes(ISO_8859_1));
                HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(),
                        getHostHeader(), Pair.of("Content-Type", "application/json"));
                os.write(("\r\n").getBytes(ISO_8859_1));
                os.flush();

                InputStream is = s.getInputStream();
                HttpUtils.Response response = HttpUtils.readResponse(is);
                int responseCode = response.getCode();

                if (!okCodes.contains(responseCode)) {
                    String error = HttpUtils.readContent(is, response);
                    throw codeToException(responseCode,
                            error != null ? error : response.getMessage());
                }

                if (output) {
                    is = HttpUtils.getResponseStream(is, response, false);
                    try (BufferedReader br = new BufferedReader(new InputStreamReader(
                            is, HttpUtils.getCharset(response)))) {
                        JSONParser parser = new JSONParser();
                        return parser.parse(br);
                    } catch (ParseException ex) {
                        throw new DockerException(ex);
                    }
                } else {
                    return null;
                }
            } finally {
                closeEndpoint(s);
            }
        } catch (MalformedURLException e) {
            throw new DockerException(e);
        } catch (IOException e) {
            throw new DockerException(e);
        }
    }

    private Object doDeleteRequest(@NonNull String action, boolean output, Set okCodes) throws DockerException {
        assert !SwingUtilities.isEventDispatchThread() : "Remote access invoked from EDT";

        try {
            Endpoint s = createEndpoint();
            try {
                OutputStream os = s.getOutputStream();
                os.write(("DELETE " + action + " HTTP/1.1\r\n").getBytes(ISO_8859_1));
                HttpUtils.configureHeaders(os, DockerConfig.getDefault().getHttpHeaders(),
                        getHostHeader(), ACCEPT_JSON_HEADER);
                os.write(("\r\n").getBytes(ISO_8859_1));
                os.flush();

                InputStream is = s.getInputStream();
                HttpUtils.Response response = HttpUtils.readResponse(is);
                int responseCode = response.getCode();

                if (!okCodes.contains(responseCode)) {
                    String error = HttpUtils.readContent(is, response);
                    throw codeToException(responseCode,
                            error != null ? error : response.getMessage());
                }

                if (output) {
                    is = HttpUtils.getResponseStream(is, response, false);
                    try (BufferedReader br = new BufferedReader(new InputStreamReader(
                            is, HttpUtils.getCharset(response)))) {
                        JSONParser parser = new JSONParser();
                        return parser.parse(br);
                    } catch (ParseException ex) {
                        throw new DockerException(ex);
                    }
                } else {
                    return null;
                }
            } finally {
                closeEndpoint(s);
            }
        } catch (MalformedURLException e) {
            throw new DockerException(e);
        } catch (IOException e) {
            throw new DockerException(e);
        }
    }

    private StatusEvent parseStatusEvent(JSONObject o) {
        boolean error = false;
        String id = (String) o.get("id");
        String status = (String) o.get("status");
        if (status == null) {
            status = (String) o.get("error");
            error = status != null;
        }
        if (status == null) {
            LOGGER.log(Level.INFO, "Unknown event {0}", o);
            return null;
        }

        String progress = (String) o.get("progress");
        StatusEvent.Progress detail = null;
        JSONObject detailObj = (JSONObject) o.get("progressDetail");
        if (detailObj != null) {
            long current = ((Number) getOrDefault(detailObj, "current", 1)).longValue();
            long total = ((Number) getOrDefault(detailObj, "total", 1)).longValue();
            detail = new StatusEvent.Progress(current, total);
        }
        return new StatusEvent(instance, id, status, progress, error, detail);
    }

    private Endpoint createEndpoint() throws IOException {
        URL realUrl = getUrl();
        try {
            if ("https".equals(realUrl.getProtocol())) { // NOI18N
                SSLContext context = ContextProvider.getInstance().getSSLContext(instance);
                return Endpoint.forSocket(context.getSocketFactory().createSocket(realUrl.getHost(), realUrl.getPort()));
            } else if ("http".equals(realUrl.getProtocol())) { // NOI18N
                Socket s = new Socket(ProxySelector.getDefault().select(realUrl.toURI()).get(0));
                int port = realUrl.getPort();
                if (port < 0) {
                    port = realUrl.getDefaultPort();
                }
                s.connect(new InetSocketAddress(realUrl.getHost(), port));
                return Endpoint.forSocket(s);
            } else if ("file".equals(realUrl.getProtocol())) {
                AFUNIXSocket s = AFUNIXSocket.newInstance();
                AFUNIXSocketAddress sockAdd = AFUNIXSocketAddress.of(new File(realUrl.getFile()));
                s.connect(sockAdd);
                return Endpoint.forSocket(s);
            } else {
                throw new IOException("Unknown protocol: " + realUrl.getProtocol());
            }
        } catch (URISyntaxException ex) {
            throw new IOException(ex);
        }
    }

    private Pair getHostHeader() throws MalformedURLException {
        URL url = getUrl();
        int port = url.getPort();
        if (port <= 0) {
            return Pair.of("Host", url.getHost()); // NOI18N
        } else {
            return Pair.of("Host", url.getHost() + ":" + port); // NOI18N
        }
    }

    private URL getUrl() throws MalformedURLException {
        String url = instance.getUrl();
        if (url.startsWith("tcp://")) { // NOI18N
            url = "http://" + url.substring(6); // NOI18N
        } else if (url.startsWith("unix://")) { // NOI18N
            url = "file://" + url.substring(7); // NOI18N
        }
        return new URL(url);
    }

    private static JSONObject createAuthObject(Credentials credentials) {
        JSONObject value = new JSONObject();
        if (credentials == null) {
            value.put("auth", ""); // NOI18N
            value.put("email", ""); // NOI18N
        } else {
            value.put("username", credentials.getUsername()); // NOI18N
            value.put("password", new String(credentials.getPassword())); // NOI18N
            value.put("email", credentials.getEmail()); // NOI18N
            value.put("serveraddress", credentials.getRegistry()); // NOI18N
            value.put("auth", ""); // NOI18N
        }
        return value;
    }

    private static String getAuthenticationFailure(StatusEvent e) {
        if (!e.isError()) {
            return null;
        }
        // this is how the docker client handles it
        // (as the server returns HTTP 200 anyway)
        if (e.getMessage().contains("Authentication is required")
                || e.getMessage().contains("Status 401")
                || e.getMessage().contains("401 Unauthorized")
                || e.getMessage().contains("status code 401")) {
            return e.getMessage();
        }
        return null;
    }

    private static DockerException codeToException(int code, String message) {
        if (code == HttpURLConnection.HTTP_CONFLICT) {
            return new DockerConflictException(message);
        } else if (code == HttpURLConnection.HTTP_UNAUTHORIZED) {
            return new DockerAuthenticationException(message);
        }
        return new DockerRemoteException(code, message);
    }

    private static String readEventObject(Reader is) throws IOException {
        StringWriter sw = new StringWriter();
        int b;
        int balance = -1;
        while ((b = is.read()) != -1) {
            if (balance < 0) {
                if (b == '{') {
                    balance = 1;
                    sw.write(b);
                }
                continue;
            }
            if (b == '{') {
                balance++;
            } else if (b == '}') {
                balance--;
            }
            sw.write(b);
            if (balance == 0) {
                return sw.toString();
            }
        }
        return null;
    }

    private static void closeEndpoint(Endpoint s) {
        if (s != null) {
            try {
                s.close();
            } catch (IOException ex) {
                LOGGER.log(Level.INFO, null, ex);
            }
        }
    }

    private static Object getOrDefault(Map map, Object key, Object def) {
        Object ret = map.get(key);
        if (ret == null) {
            ret = def;
        }
        return ret;
    }

    private static String getImage(DockerTag tag) {
        String id = tag.getTag();
        if (id.equals(":")) { // NOI18N
            id = tag.getImage().getId();
        }
        return id;
    }

    public JSONObject getRunningProcessesList(DockerContainer container) throws DockerException {
        JSONObject value = (JSONObject) doGetRequest(Container.getUrlPath() + container.getId() + "/top",
                Collections.singleton(HttpURLConnection.HTTP_OK));
        return value;
    }

    private static class DirectFetcher implements StreamItem.Fetcher {

        private final InputStream is;

        private final byte[] buffer = new byte[1024];

        public DirectFetcher(InputStream is) {
            this.is = is;
        }

        @Override
        public StreamItem fetch() {
            try {
                int count = is.read(buffer);
                if (count < 0) {
                    return null;
                }
                return new StreamItem(ByteBuffer.wrap(buffer, 0, count), false);
            } catch (IOException ex) {
                LOGGER.log(Level.FINE, null, ex);
                return null;
            }
        }

    }

    private static class EmptyStreamResult implements StreamResult {

        private final OutputStream os = new NullOutputStream();

        private final InputStream is = new NullInputStream();

        private final boolean tty;

        public EmptyStreamResult(boolean tty) {
            this.tty = tty;
        }

        @Override
        public OutputStream getStdIn() {
            return os;
        }

        @Override
        public InputStream getStdOut() {
            return is;
        }

        @Override
        public InputStream getStdErr() {
            return null;
        }

        @Override
        public boolean hasTty() {
            return tty;
        }

        @Override
        public Charset getCharset() {
            return UTF_8;
        }

        @Override
        public void close() throws IOException {
            // noop
        }
    }

    private static class CancelHandler {

        private Endpoint endpoint;

        private boolean cancelled;

        public synchronized void setEndpoint(Endpoint endpoint) {
            this.endpoint = endpoint;
        }

        public synchronized void cancel() {
            if (endpoint != null) {
                closeEndpoint(endpoint);
                endpoint = null;
                cancelled = true;
            }
        }

        public synchronized boolean isCancelled() {
            return cancelled;
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy