Skip to content

Commit 9be9c5e

Browse files
authored
Move callbacks to the API package, add ResultCallback.Adapter (docker-java#1321)
These classes belong to the API and essential for calling some of the API methods. Also, sometimes they are not needed, actually, but the current API (`ResultCallbackTemplate`) is hard to use due to the generic signature, hence the addition of `ResultCallback.Adapter`.
1 parent 35ad7d9 commit 9be9c5e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+403
-93
lines changed

docker-java-api/src/main/java/com/github/dockerjava/api/async/ResultCallback.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
* Result callback
77
*/
88
public interface ResultCallback<A_RES_T> extends Closeable {
9+
10+
class Adapter<A_RES_T> extends ResultCallbackTemplate<Adapter<A_RES_T>, A_RES_T> {
11+
@Override
12+
public void onNext(A_RES_T object) {
13+
14+
}
15+
}
16+
917
/**
1018
* Called when the async processing starts respectively when the response arrives from the server. The passed {@link Closeable} can be
1119
* used to close/interrupt the processing.

docker-java-api/src/main/java/com/github/dockerjava/api/command/AsyncDockerCmd.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package com.github.dockerjava.api.command;
55

66
import com.github.dockerjava.api.async.ResultCallback;
7+
import com.github.dockerjava.api.async.ResultCallbackTemplate;
78

89
/**
910
*
@@ -15,4 +16,7 @@ public interface AsyncDockerCmd<CMD_T extends AsyncDockerCmd<CMD_T, A_RES_T>, A_
1516

1617
<T extends ResultCallback<A_RES_T>> T exec(T resultCallback);
1718

19+
default ResultCallbackTemplate<?, A_RES_T> start() {
20+
return exec(new ResultCallback.Adapter<>());
21+
}
1822
}

docker-java-api/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ public interface BuildImageCmd extends AsyncDockerCmd<BuildImageCmd, BuildRespon
223223
*/
224224
BuildImageCmd withTarget(String target);
225225

226+
@Override
227+
default BuildImageResultCallback start() {
228+
return exec(new BuildImageResultCallback());
229+
}
230+
226231
interface Exec extends DockerCmdAsyncExec<BuildImageCmd, BuildResponseItem> {
227232
}
228233

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Created on 21.07.2015
3+
*/
4+
package com.github.dockerjava.api.command;
5+
6+
import com.github.dockerjava.api.async.ResultCallbackTemplate;
7+
import com.github.dockerjava.api.exception.DockerClientException;
8+
import com.github.dockerjava.api.model.BuildResponseItem;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import java.util.concurrent.TimeUnit;
13+
14+
/**
15+
*
16+
* @author Marcus Linke
17+
*
18+
*/
19+
public class BuildImageResultCallback extends ResultCallbackTemplate<BuildImageResultCallback, BuildResponseItem> {
20+
21+
private static final Logger LOGGER = LoggerFactory.getLogger(BuildImageResultCallback.class);
22+
23+
private String imageId;
24+
25+
private String error;
26+
27+
@Override
28+
public void onNext(BuildResponseItem item) {
29+
if (item.isBuildSuccessIndicated()) {
30+
this.imageId = item.getImageId();
31+
} else if (item.isErrorIndicated()) {
32+
this.error = item.getError();
33+
}
34+
LOGGER.debug(item.toString());
35+
}
36+
37+
/**
38+
* Awaits the image id from the response stream.
39+
*
40+
* @throws DockerClientException
41+
* if the build fails.
42+
*/
43+
public String awaitImageId() {
44+
try {
45+
awaitCompletion();
46+
} catch (InterruptedException e) {
47+
throw new DockerClientException("", e);
48+
}
49+
50+
return getImageId();
51+
}
52+
53+
/**
54+
* Awaits the image id from the response stream.
55+
*
56+
* @throws DockerClientException
57+
* if the build fails or the timeout occurs.
58+
*/
59+
public String awaitImageId(long timeout, TimeUnit timeUnit) {
60+
try {
61+
awaitCompletion(timeout, timeUnit);
62+
} catch (InterruptedException e) {
63+
throw new DockerClientException("Awaiting image id interrupted: ", e);
64+
}
65+
66+
return getImageId();
67+
}
68+
69+
private String getImageId() {
70+
if (imageId != null) {
71+
return imageId;
72+
}
73+
74+
if (error == null) {
75+
throw new DockerClientException("Could not build image");
76+
}
77+
78+
throw new DockerClientException("Could not build image: " + error);
79+
}
80+
}

docker-java-api/src/main/java/com/github/dockerjava/api/command/PullImageCmd.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.dockerjava.api.command;
22

3+
import com.github.dockerjava.api.async.ResultCallback;
34
import com.github.dockerjava.api.model.AuthConfig;
45
import com.github.dockerjava.api.model.PullResponseItem;
56

@@ -41,6 +42,11 @@ public interface PullImageCmd extends AsyncDockerCmd<PullImageCmd, PullResponseI
4142

4243
PullImageCmd withAuthConfig(AuthConfig authConfig);
4344

45+
@Override
46+
default ResultCallback.Adapter<PullResponseItem> start() {
47+
return exec(new PullImageResultCallback());
48+
}
49+
4450
interface Exec extends DockerCmdAsyncExec<PullImageCmd, PullResponseItem> {
4551
}
4652
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Created on 21.07.2015
3+
*/
4+
package com.github.dockerjava.api.command;
5+
6+
import com.github.dockerjava.api.async.ResultCallback;
7+
import com.github.dockerjava.api.exception.DockerClientException;
8+
import com.github.dockerjava.api.model.PullResponseItem;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import javax.annotation.CheckForNull;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
16+
/**
17+
*
18+
* @author Marcus Linke
19+
*
20+
*/
21+
class PullImageResultCallback extends ResultCallback.Adapter<PullResponseItem> {
22+
23+
private static final Logger LOGGER = LoggerFactory.getLogger(PullImageResultCallback.class);
24+
25+
private boolean isSwarm = false;
26+
private Map<String, PullResponseItem> results = null;
27+
28+
@CheckForNull
29+
private PullResponseItem latestItem = null;
30+
31+
@Override
32+
public void onNext(PullResponseItem item) {
33+
// only do it once
34+
if (results == null && latestItem == null) {
35+
checkForDockerSwarmResponse(item);
36+
}
37+
38+
if (isSwarm) {
39+
handleDockerSwarmResponse(item);
40+
} else {
41+
handleDockerClientResponse(item);
42+
}
43+
44+
LOGGER.debug(item.toString());
45+
}
46+
47+
private void checkForDockerSwarmResponse(PullResponseItem item) {
48+
if (item.getStatus().matches("Pulling\\s.+\\.{3}$")) {
49+
isSwarm = true;
50+
LOGGER.debug("Communicating with Docker Swarm.");
51+
}
52+
}
53+
54+
private void handleDockerSwarmResponse(final PullResponseItem item) {
55+
if (results == null) {
56+
results = new HashMap<>();
57+
}
58+
59+
// Swarm terminates a pull sometimes with an empty line.
60+
// Therefore keep first success message
61+
PullResponseItem currentItem = results.get(item.getId());
62+
if (currentItem == null || !currentItem.isPullSuccessIndicated()) {
63+
results.put(item.getId(), item);
64+
}
65+
}
66+
67+
private void handleDockerClientResponse(PullResponseItem item) {
68+
latestItem = item;
69+
}
70+
71+
private void checkDockerSwarmPullSuccessful() {
72+
if (results.isEmpty()) {
73+
throw new DockerClientException("Could not pull image through Docker Swarm");
74+
} else {
75+
boolean pullFailed = false;
76+
StringBuilder sb = new StringBuilder();
77+
78+
for (PullResponseItem pullResponseItem : results.values()) {
79+
if (!pullResponseItem.isPullSuccessIndicated()) {
80+
pullFailed = true;
81+
sb.append("[" + pullResponseItem.getId() + ":" + messageFromPullResult(pullResponseItem) + "]");
82+
}
83+
}
84+
85+
if (pullFailed) {
86+
throw new DockerClientException("Could not pull image: " + sb.toString());
87+
}
88+
}
89+
}
90+
91+
private void checkDockerClientPullSuccessful() {
92+
if (latestItem == null) {
93+
throw new DockerClientException("Could not pull image");
94+
} else if (!latestItem.isPullSuccessIndicated()) {
95+
throw new DockerClientException("Could not pull image: " + messageFromPullResult(latestItem));
96+
}
97+
}
98+
99+
private String messageFromPullResult(PullResponseItem pullResponseItem) {
100+
return (pullResponseItem.getError() != null) ? pullResponseItem.getError() : pullResponseItem.getStatus();
101+
}
102+
103+
@Override
104+
protected void throwFirstError() {
105+
super.throwFirstError();
106+
107+
if (isSwarm) {
108+
checkDockerSwarmPullSuccessful();
109+
} else {
110+
checkDockerClientPullSuccessful();
111+
}
112+
}
113+
}

docker-java-api/src/main/java/com/github/dockerjava/api/command/PushImageCmd.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import javax.annotation.CheckForNull;
44
import javax.annotation.Nonnull;
5+
import javax.annotation.Nullable;
56

67
import com.github.dockerjava.api.async.ResultCallback;
8+
import com.github.dockerjava.api.exception.DockerClientException;
79
import com.github.dockerjava.api.exception.NotFoundException;
810
import com.github.dockerjava.api.model.AuthConfig;
911
import com.github.dockerjava.api.model.PushResponseItem;
@@ -46,6 +48,31 @@ public interface PushImageCmd extends AsyncDockerCmd<PushImageCmd, PushResponseI
4648
@Override
4749
<T extends ResultCallback<PushResponseItem>> T exec(T resultCallback);
4850

51+
@Override
52+
default ResultCallback.Adapter<PushResponseItem> start() {
53+
return exec(new ResultCallback.Adapter<PushResponseItem>() {
54+
55+
@Nullable
56+
private PushResponseItem latestItem = null;
57+
58+
@Override
59+
public void onNext(PushResponseItem item) {
60+
this.latestItem = item;
61+
}
62+
63+
@Override
64+
protected void throwFirstError() {
65+
super.throwFirstError();
66+
67+
if (latestItem == null) {
68+
throw new DockerClientException("Could not push image");
69+
} else if (latestItem.isErrorIndicated()) {
70+
throw new DockerClientException("Could not push image: " + latestItem.getError());
71+
}
72+
}
73+
});
74+
}
75+
4976
interface Exec extends DockerCmdAsyncExec<PushImageCmd, PushResponseItem> {
5077
}
5178
}

docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public interface WaitContainerCmd extends AsyncDockerCmd<WaitContainerCmd, WaitR
2626
@Override
2727
<T extends ResultCallback<WaitResponse>> T exec(T resultCallback);
2828

29+
@Override
30+
default WaitContainerResultCallback start() {
31+
return exec(new WaitContainerResultCallback());
32+
}
33+
2934
interface Exec extends DockerCmdAsyncExec<WaitContainerCmd, WaitResponse> {
3035
}
3136

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

docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerResultCallback.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* @author Marcus Linke
1515
*
1616
*/
17+
@Deprecated
1718
public class AttachContainerResultCallback extends ResultCallbackTemplate<AttachContainerResultCallback, Frame> {
1819

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

0 commit comments

Comments
 (0)