Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 9 additions & 25 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@

<version.slf4j>1.6.1</version.slf4j>

<jersey.version>1.18</jersey.version>
<jersey.version>2.11</jersey.version>
<jersey-apache-client4.version>1.9</jersey-apache-client4.version>

<jackson-jaxrs.version>2.3.3</jackson-jaxrs.version>

<httpclient.version>4.2.5</httpclient.version>
<commons-compress.version>1.5</commons-compress.version>
<commons-codec.version>1.8</commons-codec.version>
<commons-io.version>2.3</commons-io.version>
<commons-lang.version>2.6</commons-lang.version>
<slf4j-api.version>1.7.5</slf4j-api.version>
Expand Down Expand Up @@ -87,38 +88,21 @@
<version>${jackson-jaxrs.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-jetty-connector</artifactId>
<version>${jersey.version}</version>
</dependency>

<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
<version>${jersey-apache-client4.version}</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
Expand Down
124 changes: 49 additions & 75 deletions src/main/java/com/github/dockerjava/client/DockerClient.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
package com.github.dockerjava.client;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.commons.io.IOUtils.closeQuietly;

import java.io.*;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.github.dockerjava.client.command.*;

import com.github.dockerjava.client.model.AuthConfig;
import com.github.dockerjava.client.utils.JsonClientFilter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;

import com.github.dockerjava.client.model.AuthConfig;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import java.io.*;

import com.github.dockerjava.client.utils.JsonClientFilter;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.apache4.ApacheHttpClient4;
import com.sun.jersey.client.apache4.ApacheHttpClient4Handler;
import static com.google.common.base.Preconditions.checkNotNull;

/**
* @author Konstantin Pelykh ([email protected])
Expand All @@ -36,7 +25,7 @@ public class DockerClient implements Closeable {
private final Client client;

private final CommandFactory cmdFactory;
private final WebResource baseResource;
private final WebTarget baseResource;
private final DockerClientConfig dockerClientConfig;

public DockerClient() {
Expand All @@ -61,51 +50,35 @@ public DockerClient(DockerClientConfig dockerClientConfig, CommandFactory cmdFac
this.cmdFactory = cmdFactory;
this.dockerClientConfig = dockerClientConfig;

HttpClient httpClient = getPoolingHttpClient(dockerClientConfig);
ClientConfig clientConfig = new DefaultClientConfig();
client = new ApacheHttpClient4(new ApacheHttpClient4Handler(httpClient,
null, false), clientConfig);

if(dockerClientConfig.getReadTimeout() != null) {
client.setReadTimeout(dockerClientConfig.getReadTimeout());
}

client.addFilter(new JsonClientFilter());
ClientConfig clientConfig = new ClientConfig();

if (dockerClientConfig.isLoggingFilterEnabled())
client.addFilter(new SelectiveLoggingFilter());
if (dockerClientConfig.getReadTimeout() != null) {
clientConfig.property(ClientProperties.READ_TIMEOUT, dockerClientConfig.getReadTimeout());
}

WebResource webResource = client.resource(dockerClientConfig.getUri());

if(dockerClientConfig.getVersion() != null) {
baseResource = webResource.path("v" + dockerClientConfig.getVersion());
} else {
baseResource = webResource;
}
}
clientConfig.register(JsonClientFilter.class);
clientConfig.register(JacksonJsonProvider.class);

private HttpClient getPoolingHttpClient(DockerClientConfig dockerClientConfig) {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", dockerClientConfig.getUri().getPort(),
PlainSocketFactory.getSocketFactory()));
schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory
.getSocketFactory()));
if (dockerClientConfig.isLoggingFilterEnabled()) {
clientConfig.register(SelectiveLoggingFilter.class);
}

PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
// Increase max total connection
cm.setMaxTotal(1000);
// Increase default max connection per route
cm.setDefaultMaxPerRoute(1000);
client = ClientBuilder.newBuilder().withConfig(clientConfig).build();
WebTarget webResource = client.target(dockerClientConfig.getUri());

return new DefaultHttpClient(cm);
if (dockerClientConfig.getVersion() != null) {
baseResource = webResource.path("v" + dockerClientConfig.getVersion());
} else {
baseResource = webResource;
}
}

public <RES_T> RES_T execute(AbstrDockerCmd<?, RES_T> command)
throws DockerException {
return command.withBaseResource(baseResource).exec();
}

public AuthConfig authConfig() throws DockerException {
public AuthConfig authConfig() throws DockerException {
checkNotNull(dockerClientConfig.getUsername(), "Configured username is null.");
checkNotNull(dockerClientConfig.getPassword(), "Configured password is null.");
checkNotNull(dockerClientConfig.getEmail(), "Configured email is null.");
Expand Down Expand Up @@ -263,28 +236,29 @@ public TagImageCmd tagImageCmd(String imageId, String repository, String tag) {
}

// TODO This is only being used by the test code for logging. Is it really necessary?
/**
* @return The output slurped into a string.
*/
public static String asString(ClientResponse response) throws IOException {

StringWriter out = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(
response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
out.write(line + (itr.hasNext() ? "\n" : ""));
}
} finally {
closeQuietly(response.getEntityInputStream());
}
return out.toString();
}

/**
* @return The output slurped into a string.
*/
public static String asString(Response response) throws IOException {

StringWriter out = new StringWriter();
InputStream is = response.readEntity(InputStream.class);
try {
LineIterator itr = IOUtils.lineIterator(is, "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
out.write(line + (itr.hasNext() ? "\n" : ""));
}
} finally {
IOUtils.closeQuietly(is);
}
return out.toString();
}

@Override
public void close() throws IOException {
client.destroy();
client.close();
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.github.dockerjava.client;

import java.io.IOException;
import java.util.Set;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;

import com.google.common.collect.ImmutableSet;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.filter.LoggingFilter;

import org.glassfish.jersey.filter.LoggingFilter;

/**
* A version of the logging filter that will avoid trying to log entities which can cause
Expand All @@ -26,22 +26,13 @@ public class SelectiveLoggingFilter extends LoggingFilter {
.build();

@Override
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
public void filter(ClientRequestContext context) throws IOException {
// Unless the content type is in the list of those we want to ellide, then just have
// our super-class handle things.
Object contentType = request.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
if (contentType != null && SKIPPED_CONTENT.contains(contentType.toString())) {
// Skip logging this.
//
// N.B. -- I'd actually love to reproduce (or better yet just use) the logging code from
// our super-class. However, everything is private (so we can't use it) and the code
// is under a modified GPL which means we can't pull it into an ASL project. Right now
// I don't have the energy to do a clean implementation.
return getNext().handle(request);
Object contentType = context.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
if (contentType == null || !SKIPPED_CONTENT.contains(contentType.toString())) {
super.filter(context);
}

// Do what we normally would
return super.handle(request);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import java.io.IOException;

import org.apache.commons.codec.binary.Base64;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.client.DockerException;
import com.github.dockerjava.client.model.AuthConfig;
import com.google.common.base.Preconditions;
import org.apache.commons.codec.binary.Base64;

public abstract class AbstrAuthCfgDockerCmd<T extends AbstrDockerCmd<T, RES_T>, RES_T> extends
AbstrDockerCmd<T, RES_T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.sun.jersey.api.client.WebResource;

import javax.ws.rs.client.WebTarget;

public abstract class AbstrDockerCmd<T extends AbstrDockerCmd<T, RES_T>, RES_T> implements DockerCmd<RES_T> {

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

protected WebResource baseResource;
protected WebTarget baseResource;

@SuppressWarnings("unchecked")
public T withBaseResource(WebResource baseResource) {
public T withBaseResource(WebTarget baseResource) {
this.baseResource = baseResource;
return (T)this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.dockerjava.client.command;

import javax.ws.rs.ClientErrorException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;

Expand All @@ -9,10 +10,10 @@
import com.github.dockerjava.client.DockerException;
import com.github.dockerjava.client.NotFoundException;
import com.google.common.base.Preconditions;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

import static javax.ws.rs.client.Entity.entity;

/**
* Attach to container
Expand All @@ -29,7 +30,7 @@
* - true or false, if true, print timestamps for every log line.
* Defaults to false.
*/
public class AttachContainerCmd extends AbstrDockerCmd<AttachContainerCmd, ClientResponse> {
public class AttachContainerCmd extends AbstrDockerCmd<AttachContainerCmd, Response> {

private static final Logger LOGGER = LoggerFactory
.getLogger(AttachContainerCmd.class);
Expand Down Expand Up @@ -109,23 +110,20 @@ public AttachContainerCmd withLogs(boolean logs) {
return this;
}

protected ClientResponse impl() throws DockerException {
MultivaluedMap<String, String> params = new MultivaluedMapImpl();
params.add("logs", logs ? "1" : "0");
params.add("timestamps", timestamps ? "1" : "0");
params.add("stdout", stdout ? "1" : "0");
params.add("stderr", stderr ? "1" : "0");
params.add("follow", followStream ? "1" : "0");

WebResource webResource = baseResource.path(
String.format("/containers/%s/attach", containerId))
.queryParams(params);
protected Response impl() throws DockerException {
WebTarget webResource = baseResource.path("/containers/{id}/attach")
.resolveTemplate("{id}", containerId)
.queryParam("logs", logs ? "1" : "0")
.queryParam("timestamps", timestamps ? "1" : "0")
.queryParam("stdout", stdout ? "1" : "0")
.queryParam("stderr", stderr ? "1" : "0")
.queryParam("follow", followStream ? "1" : "0");

try {
LOGGER.trace("POST: {}", webResource);
return webResource.accept(MediaType.APPLICATION_OCTET_STREAM_TYPE)
.post(ClientResponse.class);
} catch (UniformInterfaceException exception) {
return webResource.request().accept(MediaType.APPLICATION_OCTET_STREAM_TYPE)
.post(entity(null, MediaType.APPLICATION_JSON), Response.class);
} catch (ClientErrorException exception) {
if (exception.getResponse().getStatus() == 400) {
throw new DockerException("bad parameter");
} else if (exception.getResponse().getStatus() == 404) {
Expand Down
Loading