Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ public static ExposedPort parse(String serialized) throws IllegalArgumentExcepti
String[] parts = serialized.split("/");
switch (parts.length) {
case 1:
return new ExposedPort(Integer.valueOf(parts[0]));
return new ExposedPort(Integer.parseInt(parts[0]));
case 2:
return new ExposedPort(Integer.valueOf(parts[0]), InternetProtocol.parse(parts[1]));
return new ExposedPort(Integer.parseInt(parts[0]), InternetProtocol.parse(parts[1]));
default:
throw new IllegalArgumentException();
}
Expand Down
137 changes: 76 additions & 61 deletions src/main/java/com/github/dockerjava/api/model/Ports.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
package com.github.dockerjava.api.model;

import static org.apache.commons.lang.StringUtils.isEmpty;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.builder.EqualsBuilder;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -23,6 +12,16 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.node.NullNode;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.builder.EqualsBuilder;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import static org.apache.commons.lang.StringUtils.isEmpty;

/**
* A container for port bindings, made available as a {@link Map} via its {@link #getBindings()} method.
Expand Down Expand Up @@ -108,69 +107,85 @@ public Map<ExposedPort, Binding[]> getBindings() {
// return bindings.toArray(new PortBinding[bindings.size()]);
// }

/**
* Creates a {@link Binding} for the given IP address and port number.
*/
public static Binding binding(String hostIp, Integer hostPort) {
return new Binding(hostIp, hostPort);
}

/**
* Creates a {@link Binding} for the given port number, leaving the IP address undefined.
*/
public static Binding binding(Integer hostPort) {
return new Binding(hostPort);
}

/**
* A {@link Binding} represents a socket on the Docker host that is used in a {@link PortBinding}. It is characterized by an
* {@link #getHostIp() IP address} and a {@link #getHostPort() port number}. Both properties may be <code>null</code> in order to let
* Docker assign them dynamically/using defaults.
* {@link #getHostIp() IP address} and a {@link #getHostPortSpec() port spec}. Both properties may be <code>null</code> in order to
* let Docker assign them dynamically/using defaults.
*
* @see Ports#bind(ExposedPort, Binding)
* @see ExposedPort
*/
public static class Binding {

private final String hostIp;

private final Integer hostPort;

/**
* Creates a {@link Binding} for the given {@link #getHostIp() IP address} and {@link #getHostPort() port number}.
* Creates a {@link Binding} for the given {@link #getHostPortSpec() port spec}, leaving the {@link #getHostIp() IP address}
* undefined.
*
* @see Ports#bind(ExposedPort, Binding)
* @see ExposedPort
*/
public Binding(String hostIp, Integer hostPort) {
this.hostIp = isEmpty(hostIp) ? null : hostIp;
this.hostPort = hostPort;
public static Binding bindPortSpec(String portSpec) {
return new Binding(null, portSpec);
}

/**
* Creates a {@link Binding} for the given {@link #getHostPort() port number}, leaving the {@link #getHostIp() IP address}
* Creates a {@link Binding} for the given {@link #getHostIp() IP address}, leaving the {@link #getHostPortSpec() port spec}
* undefined.
*/
public static Binding bindIp(String hostIp) {
return new Binding(hostIp, null);
}

/**
* Creates a {@link Binding} for the given {@link #getHostIp() IP address} and port number.
*/
public static Binding bindIpAndPort(String hostIp, int port) {
return new Binding(hostIp, "" + port);
}

/**
* Creates a {@link Binding} for the given {@link #getHostIp() IP address} and port range.
*/
public static Binding bindIpAndPortRange(String hostIp, int lowPort, int highPort) {
return new Binding(hostIp, lowPort + "-" + highPort);
}

/**
* Creates a {@link Binding} for the given port range, leaving the {@link #getHostIp() IP address}
* undefined.
*
* @see Ports#bind(ExposedPort, Binding)
* @see ExposedPort
*/
public Binding(Integer hostPort) {
this(null, hostPort);
public static Binding bindPortRange(int lowPort, int highPort) {
return bindIpAndPortRange(null, lowPort, highPort);
}

/**
* Creates a {@link Binding} for the given {@link #getHostIp() IP address}, leaving the {@link #getHostPort() port number}
* Creates a {@link Binding} for the given port leaving the {@link #getHostIp() IP address}
* undefined.
*/
public Binding(String hostIp) {
this(hostIp, null);
public static Binding bindPort(int port) {
return bindIpAndPort(null, port);
}

/**
* Creates a {@link Binding} with both {@link #getHostIp() IP address} and {@link #getHostPort() port number} undefined.
* Creates an empty {@link Binding}.
*/
public Binding() {
this(null, null);
public static Binding empty() {
return new Binding(null, null);
}

private final String hostIp;

private final String hostPortSpec;

/**
* Creates a {@link Binding} for the given {@link #getHostIp() host IP address} and {@link #getHostPortSpec() host port spec}.
*
* @see Ports#bind(ExposedPort, Binding)
* @see ExposedPort
*/
public Binding(String hostIp, String hostPortSpec) {
this.hostIp = isEmpty(hostIp) ? null : hostIp;
this.hostPortSpec = hostPortSpec;
}

/**
Expand All @@ -182,16 +197,17 @@ public String getHostIp() {
}

/**
* @return the port number on the Docker host. May be <code>null</code>, in which case Docker will dynamically assign a port.
* @return the port spec for the binding on the Docker host. May reference a single port ("1234"), a port range ("1234-2345") or
* <code>null</code>, in which case Docker will dynamically assign a port.
*/
public Integer getHostPort() {
return hostPort;
public String getHostPortSpec() {
return hostPortSpec;
}

/**
* Parses a textual host and port specification (as used by the Docker CLI) to a {@link Binding}.
* <p>
* Legal syntax: <code>IP|IP:port|port</code>
* Legal syntax: <code>IP|IP:portSpec|portSpec</code> where <code>portSpec</code> is either a single port or a port range
*
* @param serialized
* serialized the specification, e.g. <code>127.0.0.1:80</code>
Expand All @@ -202,16 +218,16 @@ public Integer getHostPort() {
public static Binding parse(String serialized) throws IllegalArgumentException {
try {
if (serialized.isEmpty()) {
return new Binding();
return Binding.empty();
}

String[] parts = serialized.split(":");
switch (parts.length) {
case 2: {
return new Binding(parts[0], Integer.valueOf(parts[1]));
return new Binding(parts[0], parts[1]);
}
case 1: {
return parts[0].contains(".") ? new Binding(parts[0]) : new Binding(Integer.valueOf(parts[0]));
return parts[0].contains(".") ? Binding.bindIp(parts[0]) : Binding.bindPortSpec(parts[0]);
}
default: {
throw new IllegalArgumentException();
Expand All @@ -231,19 +247,19 @@ public static Binding parse(String serialized) throws IllegalArgumentException {
@Override
public String toString() {
if (isEmpty(hostIp)) {
return Integer.toString(hostPort);
} else if (hostPort == null) {
return hostPortSpec;
} else if (hostPortSpec == null) {
return hostIp;
} else {
return hostIp + ":" + hostPort;
return hostIp + ":" + hostPortSpec;
}
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Binding) {
Binding other = (Binding) obj;
return new EqualsBuilder().append(hostIp, other.getHostIp()).append(hostPort, other.getHostPort())
return new EqualsBuilder().append(hostIp, other.getHostIp()).append(hostPortSpec, other.getHostPortSpec())
.isEquals();
} else {
return super.equals(obj);
Expand All @@ -270,7 +286,7 @@ public Ports deserialize(JsonParser jsonParser, DeserializationContext deseriali
JsonNode bindingNode = bindingsArray.get(i);
if (!bindingNode.equals(NullNode.getInstance())) {
String hostIp = bindingNode.get("HostIp").textValue();
int hostPort = bindingNode.get("HostPort").asInt();
String hostPort = bindingNode.get("HostPort").textValue();
out.bind(ExposedPort.parse(portNode.getKey()), new Binding(hostIp, hostPort));
}
}
Expand All @@ -294,8 +310,7 @@ public void serialize(Ports portBindings, JsonGenerator jsonGen, SerializerProvi
for (Binding binding : entry.getValue()) {
jsonGen.writeStartObject();
jsonGen.writeStringField("HostIp", binding.getHostIp() == null ? "" : binding.getHostIp());
jsonGen.writeStringField("HostPort", binding.getHostPort() == null ? "" : binding.getHostPort()
.toString());
jsonGen.writeStringField("HostPort", binding.getHostPortSpec() == null ? "" : binding.getHostPortSpec());
jsonGen.writeEndObject();
}
jsonGen.writeEndArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsNot.not;
import static org.testng.Assert.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;

/**
* Tests for {@link InspectContainerResponse}.
Expand Down
11 changes: 6 additions & 5 deletions src/test/java/com/github/dockerjava/api/model/BindingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ public class BindingTest {

@Test
public void parseIpAndPort() {
assertEquals(Binding.parse("127.0.0.1:80"), Ports.binding("127.0.0.1", 80));
assertEquals(Binding.parse("127.0.0.1:80"), Binding.bindIpAndPort("127.0.0.1", 80));
}

@Test
public void parsePortOnly() {
assertEquals(Binding.parse("80"), Ports.binding(null, 80));
assertEquals(Binding.parse("80"), Binding.bindPort(80));
}

@Test
public void parseIPOnly() {
assertEquals(Binding.parse("127.0.0.1"), Ports.binding("127.0.0.1", null));
assertEquals(Binding.parse("127.0.0.1"), Binding.bindIp("127.0.0.1"));
}

@Test
public void parseEmptyString() {
assertEquals(Binding.parse(""), Ports.binding(null, null));
assertEquals(Binding.parse(""), Binding.empty());
}

@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Error parsing Binding 'nonsense'")
// Strings can be used since it can be a range. Let the docker daemon do the validation.
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Error parsing Binding 'nonsense'", enabled = false)
public void parseInvalidInput() {
Binding.parse("nonsense");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,35 @@ public class PortBindingTest {
@Test
public void fullDefinition() {
assertEquals(PortBinding.parse("127.0.0.1:80:8080/tcp"),
new PortBinding(new Binding("127.0.0.1", 80), TCP_8080));
new PortBinding(Binding.bindIpAndPort("127.0.0.1", 80), TCP_8080));
}

@Test
public void noProtocol() {
assertEquals(PortBinding.parse("127.0.0.1:80:8080"), new PortBinding(new Binding("127.0.0.1", 80), TCP_8080));
assertEquals(PortBinding.parse("127.0.0.1:80:8080"), new PortBinding(Binding.bindIpAndPort("127.0.0.1", 80), TCP_8080));
}

@Test
public void noHostIp() {
assertEquals(PortBinding.parse("80:8080/tcp"), new PortBinding(new Binding(80), TCP_8080));
assertEquals(PortBinding.parse("80:8080/tcp"), new PortBinding(Binding.bindPort(80), TCP_8080));
}

@Test
public void portsOnly() {
assertEquals(PortBinding.parse("80:8080"), new PortBinding(new Binding(80), TCP_8080));
assertEquals(PortBinding.parse("80:8080"), new PortBinding(Binding.bindPort(80), TCP_8080));
}

@Test
public void exposedPortOnly() {
assertEquals(PortBinding.parse("8080"), new PortBinding(new Binding(), TCP_8080));
assertEquals(PortBinding.parse("8080"), new PortBinding(Binding.empty(), TCP_8080));
}

@Test
public void dynamicHostPort() {
assertEquals(PortBinding.parse("127.0.0.1::8080"), new PortBinding(new Binding("127.0.0.1"), TCP_8080));
assertEquals(PortBinding.parse("127.0.0.1::8080"), new PortBinding(Binding.bindIp("127.0.0.1"), TCP_8080));
}

@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Error parsing PortBinding 'nonsense'")
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Error parsing PortBinding 'nonsense'", enabled = false)
public void parseInvalidInput() {
PortBinding.parse("nonsense");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.github.dockerjava.api.model;

import static org.testng.Assert.assertEquals;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.model.Ports.Binding;
import org.testng.annotations.Test;

import java.util.Map;

import org.testng.annotations.Test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.model.Ports.Binding;
import static org.testng.Assert.assertEquals;

public class Ports_SerializingTest {
private final ObjectMapper objectMapper = new ObjectMapper();
Expand All @@ -24,15 +23,15 @@ public void deserializingPortWithMultipleBindings() throws Exception {

Binding[] bindings = map.get(ExposedPort.tcp(80));
assertEquals(bindings.length, 2);
assertEquals(bindings[0], new Binding("10.0.0.1", 80));
assertEquals(bindings[1], new Binding("10.0.0.2", 80));
assertEquals(bindings[0], new Binding("10.0.0.1", "80"));
assertEquals(bindings[1], new Binding("10.0.0.2", "80"));
}

@Test
public void serializingPortWithMultipleBindings() throws Exception {
Ports ports = new Ports();
ports.bind(ExposedPort.tcp(80), new Binding("10.0.0.1", 80));
ports.bind(ExposedPort.tcp(80), new Binding("10.0.0.2", 80));
ports.bind(ExposedPort.tcp(80), new Binding("10.0.0.1", "80"));
ports.bind(ExposedPort.tcp(80), new Binding("10.0.0.2", "80"));
assertEquals(objectMapper.writeValueAsString(ports), jsonWithDoubleBindingForOnePort);
}

Expand Down
Loading