Skip to content

Commit 7a15817

Browse files
author
Marcus Linke
committed
Fix issue docker-java#348
1 parent 520ed0f commit 7a15817

14 files changed

Lines changed: 190 additions & 33 deletions
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.github.dockerjava.api.command;
22

33
import com.github.dockerjava.api.NotFoundException;
4+
import com.github.dockerjava.api.async.ResultCallback;
5+
import com.github.dockerjava.api.model.BuildResponseItem;
6+
import com.github.dockerjava.api.model.WaitResponse;
47

58
/**
69
* Wait a container
710
*
811
* Block until container stops, then returns its exit code
912
*/
10-
public interface WaitContainerCmd extends SyncDockerCmd<Integer> {
13+
public interface WaitContainerCmd extends AsyncDockerCmd<WaitContainerCmd, WaitResponse> {
1114

1215
public String getContainerId();
1316

@@ -18,9 +21,9 @@ public interface WaitContainerCmd extends SyncDockerCmd<Integer> {
1821
* container not found
1922
*/
2023
@Override
21-
public Integer exec() throws NotFoundException;
24+
public <T extends ResultCallback<WaitResponse>> T exec(T resultCallback);
2225

23-
public static interface Exec extends DockerCmdSyncExec<WaitContainerCmd, Integer> {
26+
public static interface Exec extends DockerCmdAsyncExec<WaitContainerCmd, WaitResponse> {
2427
}
2528

2629
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
6+
7+
/**
8+
* Represents a wait container command response
9+
*/
10+
@JsonIgnoreProperties(ignoreUnknown = false)
11+
public class WaitResponse {
12+
13+
@JsonProperty("StatusCode")
14+
private Integer statusCode;
15+
16+
public Integer getStatusCode() {
17+
return statusCode;
18+
}
19+
}

src/main/java/com/github/dockerjava/core/async/ResultCallbackTemplate.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.slf4j.LoggerFactory;
1313

1414
import com.github.dockerjava.api.async.ResultCallback;
15+
import com.google.common.base.Throwables;
1516

1617
/**
1718
* Abstract template implementation of {@link ResultCallback}
@@ -30,6 +31,8 @@ public abstract class ResultCallbackTemplate<RC_T extends ResultCallback<A_RES_T
3031

3132
private boolean closed = false;
3233

34+
private Throwable firstError = null;
35+
3336
@Override
3437
public void onStart(Closeable stream) {
3538
this.stream = stream;
@@ -38,12 +41,15 @@ public void onStart(Closeable stream) {
3841

3942
@Override
4043
public void onError(Throwable throwable) {
44+
4145
if (closed)
4246
return;
4347

48+
if (this.firstError == null)
49+
this.firstError = throwable;
50+
4451
try {
4552
LOGGER.error("Error during callback", throwable);
46-
throw new RuntimeException(throwable);
4753
} finally {
4854
try {
4955
close();
@@ -76,6 +82,8 @@ public void close() throws IOException {
7682
@SuppressWarnings("unchecked")
7783
public RC_T awaitCompletion() throws InterruptedException {
7884
completed.await();
85+
// eventually (re)throws RuntimeException
86+
getFirstError();
7987
return (RC_T) this;
8088
}
8189

@@ -87,4 +95,13 @@ public RC_T awaitCompletion(long timeout, TimeUnit timeUnit) throws InterruptedE
8795
completed.await(timeout, timeUnit);
8896
return (RC_T) this;
8997
}
98+
99+
protected RuntimeException getFirstError() {
100+
if (firstError != null) {
101+
// this call throws a RuntimeException
102+
return Throwables.propagate(firstError);
103+
} else {
104+
return null;
105+
}
106+
}
90107
}

src/main/java/com/github/dockerjava/core/command/WaitContainerCmdImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import static com.google.common.base.Preconditions.checkNotNull;
44

55
import com.github.dockerjava.api.command.WaitContainerCmd;
6+
import com.github.dockerjava.api.model.WaitResponse;
67

78
/**
89
* Wait a container
9-
*
10+
*
1011
* Block until container stops, then returns its exit code
1112
*/
12-
public class WaitContainerCmdImpl extends AbstrDockerCmd<WaitContainerCmd, Integer> implements WaitContainerCmd {
13+
public class WaitContainerCmdImpl extends AbstrAsyncDockerCmd<WaitContainerCmd, WaitResponse> implements WaitContainerCmd {
1314

1415
private String containerId;
1516

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Created on 21.07.2015
3+
*/
4+
package com.github.dockerjava.core.command;
5+
6+
import java.util.concurrent.TimeUnit;
7+
8+
import javax.annotation.CheckForNull;
9+
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
import com.github.dockerjava.api.DockerClientException;
14+
import com.github.dockerjava.api.model.WaitResponse;
15+
import com.github.dockerjava.core.async.ResultCallbackTemplate;
16+
import com.google.common.base.Throwables;
17+
18+
/**
19+
*
20+
* @author marcus
21+
*
22+
*/
23+
public class WaitContainerResultCallback extends ResultCallbackTemplate<WaitContainerResultCallback, WaitResponse> {
24+
25+
private final static Logger LOGGER = LoggerFactory.getLogger(WaitContainerResultCallback.class);
26+
27+
@CheckForNull
28+
private WaitResponse waitResponse = null;
29+
30+
@Override
31+
public void onNext(WaitResponse waitResponse) {
32+
this.waitResponse = waitResponse;
33+
LOGGER.debug(waitResponse.toString());
34+
}
35+
36+
/**
37+
* Awaits the status code from the container.
38+
*
39+
* @throws DockerClientException
40+
* if the wait operation fails.
41+
*/
42+
public Integer awaitStatusCode() {
43+
try {
44+
awaitCompletion();
45+
} catch (InterruptedException e) {
46+
throw new DockerClientException("", e);
47+
}
48+
49+
return getStatusCode();
50+
}
51+
52+
/**
53+
* Awaits the status code from the container.
54+
*
55+
* @throws DockerClientException
56+
* if the wait operation fails.
57+
*/
58+
public Integer awaitStatusCode(long timeout, TimeUnit timeUnit) {
59+
try {
60+
awaitCompletion(timeout, timeUnit);
61+
} catch (InterruptedException e) {
62+
throw new DockerClientException("Awaiting status code interrupted: ", e);
63+
}
64+
65+
return getStatusCode();
66+
}
67+
68+
private Integer getStatusCode() {
69+
if (waitResponse == null) {
70+
throw new DockerClientException("Error while wait container");
71+
} else {
72+
return waitResponse.getStatusCode();
73+
}
74+
}
75+
}
Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package com.github.dockerjava.jaxrs;
22

3-
import com.fasterxml.jackson.databind.node.ObjectNode;
4-
import com.github.dockerjava.api.command.WaitContainerCmd;
5-
import com.github.dockerjava.core.DockerClientConfig;
6-
import org.slf4j.Logger;
7-
import org.slf4j.LoggerFactory;
3+
import static javax.ws.rs.client.Entity.entity;
84

95
import javax.ws.rs.client.WebTarget;
106
import javax.ws.rs.core.MediaType;
117

12-
public class WaitContainerCmdExec extends AbstrSyncDockerCmdExec<WaitContainerCmd, Integer> implements
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
import com.github.dockerjava.api.async.ResultCallback;
12+
import com.github.dockerjava.api.command.WaitContainerCmd;
13+
import com.github.dockerjava.api.model.WaitResponse;
14+
import com.github.dockerjava.core.DockerClientConfig;
15+
import com.github.dockerjava.core.async.JsonStreamProcessor;
16+
import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier;
17+
import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier;
18+
19+
public class WaitContainerCmdExec extends AbstrAsyncDockerCmdExec<WaitContainerCmd, WaitResponse> implements
1320
WaitContainerCmd.Exec {
1421

1522
private static final Logger LOGGER = LoggerFactory.getLogger(WaitContainerCmdExec.class);
@@ -19,14 +26,16 @@ public WaitContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerCli
1926
}
2027

2128
@Override
22-
protected Integer execute(WaitContainerCmd command) {
29+
protected AbstractCallbackNotifier<WaitResponse> callbackNotifier(WaitContainerCmd command,
30+
ResultCallback<WaitResponse> resultCallback) {
31+
2332
WebTarget webResource = getBaseResource().path("/containers/{id}/wait").resolveTemplate("id",
2433
command.getContainerId());
2534

2635
LOGGER.trace("POST: {}", webResource);
27-
ObjectNode ObjectNode = webResource.request().accept(MediaType.APPLICATION_JSON).post(null, ObjectNode.class);
2836

29-
return ObjectNode.get("StatusCode").asInt();
37+
return new POSTCallbackNotifier<WaitResponse>(new JsonStreamProcessor<WaitResponse>(
38+
WaitResponse.class), resultCallback, webResource.request().accept(MediaType.APPLICATION_JSON), entity(null, MediaType.APPLICATION_JSON));
3039
}
3140

3241
}

src/test/java/com/github/dockerjava/client/DockerClientTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import com.github.dockerjava.api.DockerException;
1818
import com.github.dockerjava.api.command.CreateContainerResponse;
19+
import com.github.dockerjava.core.command.WaitContainerResultCallback;
1920

2021
/**
2122
* Unit test for DockerClient.
@@ -61,7 +62,7 @@ public void testRunShlex() throws DockerException {
6162
CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd(commands).exec();
6263
dockerClient.startContainerCmd(container.getId());
6364

64-
int exitcode = dockerClient.waitContainerCmd(container.getId()).exec();
65+
int exitcode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode();
6566
assertThat(exitcode, equalTo(0));
6667
}
6768
}

src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ private String execBuild(BuildImageCmd buildImageCmd) throws Exception {
158158
assertThat(container.getId(), not(isEmptyString()));
159159

160160
dockerClient.startContainerCmd(container.getId()).exec();
161-
dockerClient.waitContainerCmd(container.getId()).exec();
161+
dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode();
162162

163163
return containerLog(container.getId());
164164
}

src/test/java/com/github/dockerjava/core/command/ContainerDiffCmdImplTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public void testContainerDiff() throws DockerException {
5353
assertThat(container.getId(), not(isEmptyString()));
5454
dockerClient.startContainerCmd(container.getId()).exec();
5555

56-
int exitCode = dockerClient.waitContainerCmd(container.getId()).exec();
56+
int exitCode = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode();
5757
assertThat(exitCode, equalTo(0));
5858

5959
List<ChangeLog> filesystemDiff = dockerClient.containerDiffCmd(container.getId()).exec();

src/test/java/com/github/dockerjava/core/command/FrameReaderITest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public void deleteDockerContainerImage() throws Exception {
4141
public void canCloseFrameReaderAndReadExpectedLines() throws Exception {
4242

4343
// wait for the container to be successfully executed
44-
int exitCode = dockerClient.waitContainerCmd(dockerfileFixture.getContainerId()).exec();
44+
int exitCode = dockerClient.waitContainerCmd(dockerfileFixture.getContainerId())
45+
.exec(new WaitContainerResultCallback()).awaitStatusCode();
4546
assertEquals(0, exitCode);
4647

4748
Iterator<Frame> response = getLoggingFrames().iterator();

0 commit comments

Comments
 (0)