Skip to content

Commit 0ee67be

Browse files
committed
Parser for PortBinding and Binding
This allows you to use textual port binding specifications in the format used by the Docker CLI in docker-java: StartContainerCmd.withPortBindings(PortBinding.parse("80:8080/tcp"));
1 parent 3b14b1f commit 0ee67be

File tree

4 files changed

+184
-2
lines changed

4 files changed

+184
-2
lines changed

src/main/java/com/github/dockerjava/api/model/PortBinding.java

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

3+
import org.apache.commons.lang.StringUtils;
4+
import org.apache.commons.lang.builder.EqualsBuilder;
5+
import org.apache.commons.lang.builder.HashCodeBuilder;
6+
37
import com.github.dockerjava.api.command.InspectContainerResponse.HostConfig;
48
import com.github.dockerjava.api.command.InspectContainerResponse.NetworkSettings;
59
import com.github.dockerjava.api.model.Ports.Binding;
@@ -33,4 +37,47 @@ public Binding getBinding() {
3337
public ExposedPort getExposedPort() {
3438
return exposedPort;
3539
}
40+
41+
public static PortBinding parse(String serialized) throws IllegalArgumentException {
42+
try {
43+
String[] parts = StringUtils.splitByWholeSeparator(serialized, ":");
44+
switch (parts.length) {
45+
case 3:
46+
// 127.0.0.1:80:8080/tcp
47+
return createFromSubstrings(parts[0] + ":" + parts[1], parts[2]);
48+
case 2:
49+
// 80:8080 // 127.0.0.1::8080
50+
return createFromSubstrings(parts[0], parts[1]);
51+
case 1:
52+
// 8080
53+
return createFromSubstrings("", parts[0]);
54+
default:
55+
throw new IllegalArgumentException();
56+
}
57+
} catch (Exception e) {
58+
throw new IllegalArgumentException("Error parsing PortBinding '"
59+
+ serialized + "'", e);
60+
}
61+
}
62+
63+
private static PortBinding createFromSubstrings(String binding, String exposedPort)
64+
throws IllegalArgumentException {
65+
return new PortBinding(Binding.parse(binding), ExposedPort.parse(exposedPort));
66+
}
67+
68+
@Override
69+
public boolean equals(Object obj) {
70+
if (obj instanceof PortBinding) {
71+
PortBinding other = (PortBinding) obj;
72+
return new EqualsBuilder().append(binding, other.getBinding())
73+
.append(exposedPort, other.getExposedPort()).isEquals();
74+
} else
75+
return super.equals(obj);
76+
}
77+
78+
@Override
79+
public int hashCode() {
80+
return new HashCodeBuilder().append(binding).append(exposedPort).toHashCode();
81+
}
82+
3683
}

src/main/java/com/github/dockerjava/api/model/Ports.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.dockerjava.api.model;
22

3+
import static org.apache.commons.lang.StringUtils.isEmpty;
4+
35
import java.io.IOException;
46
import java.util.HashMap;
57
import java.util.Iterator;
@@ -8,7 +10,6 @@
810

911
import org.apache.commons.lang.ArrayUtils;
1012
import org.apache.commons.lang.builder.EqualsBuilder;
11-
import org.apache.commons.lang.builder.ToStringBuilder;
1213

1314
import com.fasterxml.jackson.core.JsonGenerator;
1415
import com.fasterxml.jackson.core.JsonParser;
@@ -152,9 +153,51 @@ public int getHostPort() {
152153
return hostPort;
153154
}
154155

156+
/**
157+
* Parses a textual host and port specification (as used by the Docker CLI)
158+
* to a {@link Binding}.
159+
* <p>
160+
* Legal syntax: <code>[IP:]Port</code>
161+
*
162+
* @param serialized serialized the specification, e.g.
163+
* <code>127.0.0.1:80</code>
164+
* @return a {@link Binding} matching the specification
165+
* @throws IllegalArgumentException if the specification cannot be parsed
166+
*/
167+
public static Binding parse(String serialized) throws IllegalArgumentException {
168+
try {
169+
String[] parts = serialized.split(":");
170+
switch (parts.length) {
171+
case 2: {
172+
return new Binding(parts[0], Integer.valueOf(parts[1]));
173+
}
174+
case 1: {
175+
return new Binding(Integer.valueOf(parts[0]));
176+
}
177+
default: {
178+
throw new IllegalArgumentException();
179+
}
180+
}
181+
} catch (Exception e) {
182+
throw new IllegalArgumentException("Error parsing Binding '"
183+
+ serialized + "'");
184+
}
185+
}
186+
187+
/**
188+
* Returns a string representation of this {@link Binding} suitable
189+
* for inclusion in a JSON message.
190+
* The format is <code>[IP:]Port</code>, like the argument in {@link #parse(String)}.
191+
*
192+
* @return a string representation of this {@link Binding}
193+
*/
155194
@Override
156195
public String toString() {
157-
return ToStringBuilder.reflectionToString(this);
196+
if (isEmpty(hostIp)) {
197+
return Integer.toString(hostPort);
198+
} else {
199+
return hostIp + ":" + hostPort;
200+
}
158201
}
159202

160203
@Override
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import static org.testng.Assert.assertEquals;
4+
5+
import org.testng.annotations.Test;
6+
7+
import com.github.dockerjava.api.model.Ports.Binding;
8+
9+
public class BindingTest {
10+
11+
@Test
12+
public void parseIpAndPort() {
13+
assertEquals(Binding.parse("127.0.0.1:80"), Ports.Binding("127.0.0.1", 80));
14+
}
15+
16+
@Test
17+
public void parsePortOnly() {
18+
assertEquals(Binding.parse("80"), Ports.Binding("", 80));
19+
}
20+
21+
@Test(expectedExceptions = IllegalArgumentException.class,
22+
expectedExceptionsMessageRegExp = "Error parsing Binding 'nonsense'")
23+
public void parseInvalidInput() {
24+
Binding.parse("nonsense");
25+
}
26+
27+
@Test(expectedExceptions = IllegalArgumentException.class,
28+
expectedExceptionsMessageRegExp = "Error parsing Binding 'null'")
29+
public void parseNull() {
30+
Binding.parse(null);
31+
}
32+
33+
@Test
34+
public void toStringIpAndHost() {
35+
assertEquals(Binding.parse("127.0.0.1:80").toString(), "127.0.0.1:80");
36+
}
37+
38+
@Test
39+
public void toStringPortOnly() {
40+
assertEquals(Binding.parse("80").toString(), "80");
41+
}
42+
43+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import static org.testng.Assert.assertEquals;
4+
5+
import org.testng.annotations.Test;
6+
7+
import com.github.dockerjava.api.model.Ports.Binding;
8+
9+
public class PortBindingTest {
10+
11+
private static final ExposedPort TCP_8080 = ExposedPort.tcp(8080);
12+
13+
@Test
14+
public void fullDefinition() {
15+
assertEquals(PortBinding.parse("127.0.0.1:80:8080/tcp"),
16+
new PortBinding(new Binding("127.0.0.1", 80), TCP_8080));
17+
}
18+
19+
@Test
20+
public void noProtocol() {
21+
assertEquals(PortBinding.parse("127.0.0.1:80:8080"),
22+
new PortBinding(new Binding("127.0.0.1", 80), TCP_8080));
23+
}
24+
25+
@Test
26+
public void noHostIp() {
27+
assertEquals(PortBinding.parse("80:8080/tcp"),
28+
new PortBinding(new Binding(80), TCP_8080));
29+
}
30+
31+
@Test
32+
public void portsOnly() {
33+
assertEquals(PortBinding.parse("80:8080"),
34+
new PortBinding(new Binding(80), TCP_8080));
35+
}
36+
37+
@Test(expectedExceptions = IllegalArgumentException.class,
38+
expectedExceptionsMessageRegExp = "Error parsing PortBinding 'nonsense'")
39+
public void parseInvalidInput() {
40+
PortBinding.parse("nonsense");
41+
}
42+
43+
@Test(expectedExceptions = IllegalArgumentException.class,
44+
expectedExceptionsMessageRegExp = "Error parsing PortBinding 'null'")
45+
public void parseNull() {
46+
PortBinding.parse(null);
47+
}
48+
49+
}

0 commit comments

Comments
 (0)