Merge pull request #575 from docker-java/issue-556 · docker-java/docker-java@bf9a57a
11package com.github.dockerjava.api.model;
223-import static org.apache.commons.lang.StringUtils.isEmpty;
4-5-import java.io.IOException;
6-import java.util.HashMap;
7-import java.util.Iterator;
8-import java.util.Map;
9-import java.util.Map.Entry;
10-11-import org.apache.commons.lang.ArrayUtils;
12-import org.apache.commons.lang.builder.EqualsBuilder;
13-143import com.fasterxml.jackson.core.JsonGenerator;
154import com.fasterxml.jackson.core.JsonParser;
165import com.fasterxml.jackson.core.JsonProcessingException;
@@ -23,6 +12,16 @@
2312import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2413import com.fasterxml.jackson.databind.annotation.JsonSerialize;
2514import com.fasterxml.jackson.databind.node.NullNode;
15+import org.apache.commons.lang.ArrayUtils;
16+import org.apache.commons.lang.builder.EqualsBuilder;
17+18+import java.io.IOException;
19+import java.util.HashMap;
20+import java.util.Iterator;
21+import java.util.Map;
22+import java.util.Map.Entry;
23+24+import static org.apache.commons.lang.StringUtils.isEmpty;
26252726/**
2827 * A container for port bindings, made available as a {@link Map} via its {@link #getBindings()} method.
@@ -108,69 +107,85 @@ public Map<ExposedPort, Binding[]> getBindings() {
108107// return bindings.toArray(new PortBinding[bindings.size()]);
109108// }
110109111-/**
112- * Creates a {@link Binding} for the given IP address and port number.
113- */
114-public static Binding binding(String hostIp, Integer hostPort) {
115-return new Binding(hostIp, hostPort);
116- }
117-118-/**
119- * Creates a {@link Binding} for the given port number, leaving the IP address undefined.
120- */
121-public static Binding binding(Integer hostPort) {
122-return new Binding(hostPort);
123- }
124-125110/**
126111 * A {@link Binding} represents a socket on the Docker host that is used in a {@link PortBinding}. It is characterized by an
127- * {@link #getHostIp() IP address} and a {@link #getHostPort() port number}. Both properties may be <code>null</code> in order to let
128- * Docker assign them dynamically/using defaults.
112+ * {@link #getHostIp() IP address} and a {@link #getHostPortSpec() port spec}. Both properties may be <code>null</code> in order to
113+ * let Docker assign them dynamically/using defaults.
129114 *
130115 * @see Ports#bind(ExposedPort, Binding)
131116 * @see ExposedPort
132117 */
133118public static class Binding {
134119135-private final String hostIp;
136-137-private final Integer hostPort;
138-139120/**
140- * Creates a {@link Binding} for the given {@link #getHostIp() IP address} and {@link #getHostPort() port number}.
121+ * Creates a {@link Binding} for the given {@link #getHostPortSpec() port spec}, leaving the {@link #getHostIp() IP address}
122+ * undefined.
141123 *
142124 * @see Ports#bind(ExposedPort, Binding)
143125 * @see ExposedPort
144126 */
145-public Binding(String hostIp, Integer hostPort) {
146-this.hostIp = isEmpty(hostIp) ? null : hostIp;
147-this.hostPort = hostPort;
127+public static Binding bindPortSpec(String portSpec) {
128+return new Binding(null, portSpec);
148129 }
149130150131/**
151- * Creates a {@link Binding} for the given {@link #getHostPort() port number}, leaving the {@link #getHostIp() IP address}
132+ * Creates a {@link Binding} for the given {@link #getHostIp() IP address}, leaving the {@link #getHostPortSpec() port spec}
133+ * undefined.
134+ */
135+public static Binding bindIp(String hostIp) {
136+return new Binding(hostIp, null);
137+ }
138+139+/**
140+ * Creates a {@link Binding} for the given {@link #getHostIp() IP address} and port number.
141+ */
142+public static Binding bindIpAndPort(String hostIp, int port) {
143+return new Binding(hostIp, "" + port);
144+ }
145+146+/**
147+ * Creates a {@link Binding} for the given {@link #getHostIp() IP address} and port range.
148+ */
149+public static Binding bindIpAndPortRange(String hostIp, int lowPort, int highPort) {
150+return new Binding(hostIp, lowPort + "-" + highPort);
151+ }
152+153+/**
154+ * Creates a {@link Binding} for the given port range, leaving the {@link #getHostIp() IP address}
152155 * undefined.
153- *
154- * @see Ports#bind(ExposedPort, Binding)
155- * @see ExposedPort
156156 */
157-public Binding(Integer hostPort) {
158-this(null, hostPort);
157+public static Binding bindPortRange(int lowPort, int highPort) {
158+return bindIpAndPortRange(null, lowPort, highPort);
159159 }
160160161161/**
162- * Creates a {@link Binding} for the given {@link #getHostIp() IP address}, leaving the {@link #getHostPort() port number}
162+ * Creates a {@link Binding} for the given port leaving the {@link #getHostIp() IP address}
163163 * undefined.
164164 */
165-public Binding(String hostIp) {
166-this(hostIp, null);
165+public static Binding bindPort(int port) {
166+return bindIpAndPort(null, port);
167167 }
168168169169/**
170- * Creates a {@link Binding} with both {@link #getHostIp() IP address} and {@link #getHostPort() port number} undefined.
170+ * Creates an empty {@link Binding}.
171171 */
172-public Binding() {
173-this(null, null);
172+public static Binding empty() {
173+return new Binding(null, null);
174+ }
175+176+private final String hostIp;
177+178+private final String hostPortSpec;
179+180+/**
181+ * Creates a {@link Binding} for the given {@link #getHostIp() host IP address} and {@link #getHostPortSpec() host port spec}.
182+ *
183+ * @see Ports#bind(ExposedPort, Binding)
184+ * @see ExposedPort
185+ */
186+public Binding(String hostIp, String hostPortSpec) {
187+this.hostIp = isEmpty(hostIp) ? null : hostIp;
188+this.hostPortSpec = hostPortSpec;
174189 }
175190176191/**
@@ -182,16 +197,17 @@ public String getHostIp() {
182197 }
183198184199/**
185- * @return the port number on the Docker host. May be <code>null</code>, in which case Docker will dynamically assign a port.
200+ * @return the port spec for the binding on the Docker host. May reference a single port ("1234"), a port range ("1234-2345") or
201+ * <code>null</code>, in which case Docker will dynamically assign a port.
186202 */
187-public Integer getHostPort() {
188-return hostPort;
203+public String getHostPortSpec() {
204+return hostPortSpec;
189205 }
190206191207/**
192208 * Parses a textual host and port specification (as used by the Docker CLI) to a {@link Binding}.
193209 * <p>
194- * Legal syntax: <code>IP|IP:port|port</code>
210+ * Legal syntax: <code>IP|IP:portSpec|portSpec</code> where <code>portSpec</code> is either a single port or a port range
195211 *
196212 * @param serialized
197213 * serialized the specification, e.g. <code>127.0.0.1:80</code>
@@ -202,16 +218,16 @@ public Integer getHostPort() {
202218public static Binding parse(String serialized) throws IllegalArgumentException {
203219try {
204220if (serialized.isEmpty()) {
205-return new Binding();
221+return Binding.empty();
206222 }
207223208224String[] parts = serialized.split(":");
209225switch (parts.length) {
210226case 2: {
211-return new Binding(parts[0], Integer.valueOf(parts[1]));
227+return new Binding(parts[0], parts[1]);
212228 }
213229case 1: {
214-return parts[0].contains(".") ? new Binding(parts[0]) : new Binding(Integer.valueOf(parts[0]));
230+return parts[0].contains(".") ? Binding.bindIp(parts[0]) : Binding.bindPortSpec(parts[0]);
215231 }
216232default: {
217233throw new IllegalArgumentException();
@@ -231,19 +247,19 @@ public static Binding parse(String serialized) throws IllegalArgumentException {
231247@Override
232248public String toString() {
233249if (isEmpty(hostIp)) {
234-return Integer.toString(hostPort);
235- } else if (hostPort == null) {
250+return hostPortSpec;
251+ } else if (hostPortSpec == null) {
236252return hostIp;
237253 } else {
238-return hostIp + ":" + hostPort;
254+return hostIp + ":" + hostPortSpec;
239255 }
240256 }
241257242258@Override
243259public boolean equals(Object obj) {
244260if (obj instanceof Binding) {
245261Binding other = (Binding) obj;
246-return new EqualsBuilder().append(hostIp, other.getHostIp()).append(hostPort, other.getHostPort())
262+return new EqualsBuilder().append(hostIp, other.getHostIp()).append(hostPortSpec, other.getHostPortSpec())
247263 .isEquals();
248264 } else {
249265return super.equals(obj);
@@ -270,7 +286,7 @@ public Ports deserialize(JsonParser jsonParser, DeserializationContext deseriali
270286JsonNode bindingNode = bindingsArray.get(i);
271287if (!bindingNode.equals(NullNode.getInstance())) {
272288String hostIp = bindingNode.get("HostIp").textValue();
273-int hostPort = bindingNode.get("HostPort").asInt();
289+String hostPort = bindingNode.get("HostPort").textValue();
274290out.bind(ExposedPort.parse(portNode.getKey()), new Binding(hostIp, hostPort));
275291 }
276292 }
@@ -294,8 +310,7 @@ public void serialize(Ports portBindings, JsonGenerator jsonGen, SerializerProvi
294310for (Binding binding : entry.getValue()) {
295311jsonGen.writeStartObject();
296312jsonGen.writeStringField("HostIp", binding.getHostIp() == null ? "" : binding.getHostIp());
297-jsonGen.writeStringField("HostPort", binding.getHostPort() == null ? "" : binding.getHostPort()
298- .toString());
313+jsonGen.writeStringField("HostPort", binding.getHostPortSpec() == null ? "" : binding.getHostPortSpec());
299314jsonGen.writeEndObject();
300315 }
301316jsonGen.writeEndArray();