Andrea Campanella
Committed by Gerrit Code Review

ONOS-3562 Changing the flow instructions port to human readable format

Change-Id: Ia6b1a755bc400295600f4112cb3ebe676e533eb2
......@@ -15,18 +15,19 @@
*/
package org.onosproject.net;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.primitives.UnsignedLongs;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of a port number.
*/
......@@ -67,6 +68,7 @@ public final class PortNumber {
/**
* PortNumber instance for the logical port.
*
* @return {@link PortNumber}
*/
public PortNumber instance() {
......@@ -145,6 +147,38 @@ public final class PortNumber {
}
/**
* Returns PortNumber instance from String representation.
*
* @param s String representation equivalent to {@link PortNumber#toString()}
* @return {@link PortNumber} instance
* @throws IllegalArgumentException if given String was malformed
*/
public static PortNumber fromString(String s) {
checkNotNull(s);
checkArgument(!s.isEmpty(), "cannot be empty");
if (isAsciiDecimal(s.charAt(0))) {
// unsigned decimal string
return portNumber(s);
} else if (s.startsWith("[")) {
// named PortNumber
Matcher matcher = NAMED.matcher(s);
checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
String name = matcher.group("name");
String num = matcher.group("num");
return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
}
// Logical
if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
} else {
return Logical.valueOf(s).instance;
}
}
/**
* Indicates whether or not this port number is a reserved logical one or
* whether it corresponds to a normal physical port of a device or NIC.
*
......@@ -207,38 +241,6 @@ public final class PortNumber {
return '0' <= c && c <= '9';
}
/**
* Returns PortNumber instance from String representation.
*
* @param s String representation equivalent to {@link PortNumber#toString()}
* @return {@link PortNumber} instance
* @throws IllegalArgumentException if given String was malformed
*/
public static PortNumber fromString(String s) {
checkNotNull(s);
checkArgument(!s.isEmpty(), "cannot be empty");
if (isAsciiDecimal(s.charAt(0))) {
// unsigned decimal string
return portNumber(s);
} else if (s.startsWith("[")) {
// named PortNumber
Matcher matcher = NAMED.matcher(s);
checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
String name = matcher.group("name");
String num = matcher.group("num");
return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
}
// Logical
if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
} else {
return Logical.valueOf(s).instance;
}
}
@Override
public String toString() {
if (isLogical()) {
......
......@@ -240,9 +240,22 @@ public final class DecodeInstructionCodecHelper {
String type = json.get(InstructionCodec.TYPE).asText();
if (type.equals(Instruction.Type.OUTPUT.name())) {
PortNumber portNumber =
PortNumber.portNumber(nullIsIllegal(json.get(InstructionCodec.PORT),
InstructionCodec.PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong());
PortNumber portNumber;
if (json.get(InstructionCodec.PORT).isLong() || json.get(InstructionCodec.PORT).isInt()) {
portNumber = PortNumber
.portNumber(nullIsIllegal(json.get(InstructionCodec.PORT)
.asLong(), InstructionCodec.PORT
+ InstructionCodec.MISSING_MEMBER_MESSAGE));
} else if (json.get(InstructionCodec.PORT).isTextual()) {
portNumber = PortNumber
.fromString(nullIsIllegal(json.get(InstructionCodec.PORT)
.textValue(), InstructionCodec.PORT
+ InstructionCodec.MISSING_MEMBER_MESSAGE));
} else {
throw new IllegalArgumentException("Port value "
+ json.get(InstructionCodec.PORT).toString()
+ " is not supported");
}
return Instructions.createOutput(portNumber);
} else if (type.equals(Instruction.Type.DROP.name())) {
return Instructions.createDrop();
......
......@@ -87,8 +87,6 @@ public final class EncodeInstructionCodecHelper {
* Encode an L1 modification instruction.
*
* @param result json node that the instruction attributes are added to
* @param instruction The L1 instruction
* @param context context of the request
*/
private void encodeL1(ObjectNode result) {
L1ModificationInstruction instruction =
......@@ -244,7 +242,7 @@ public final class EncodeInstructionCodecHelper {
case OUTPUT:
final Instructions.OutputInstruction outputInstruction =
(Instructions.OutputInstruction) instruction;
result.put(InstructionCodec.PORT, outputInstruction.port().toLong());
result.put(InstructionCodec.PORT, outputInstruction.port().toString());
break;
case DROP:
......
......@@ -93,18 +93,31 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json
*/
private boolean matchOutputInstruction(JsonNode instructionJson,
Description description) {
OutputInstruction instructionToMatch = (OutputInstruction) instruction;
final String jsonType = instructionJson.get("type").textValue();
OutputInstruction instructionToMatch = (OutputInstruction) instruction;
if (!instructionToMatch.type().name().equals(jsonType)) {
description.appendText("type was " + jsonType);
return false;
}
final long jsonPort = instructionJson.get("port").asLong();
if (instructionToMatch.port().toLong() != jsonPort) {
description.appendText("port was " + jsonPort);
return false;
if (instructionJson.get("port").isLong() ||
instructionJson.get("port").isInt()) {
final long jsonPort = instructionJson.get("port").asLong();
if (instructionToMatch.port().toLong() != (jsonPort)) {
description.appendText("port was " + jsonPort);
return false;
}
} else if (instructionJson.get("port").isTextual()) {
final String jsonPort = instructionJson.get("port").textValue();
if (!instructionToMatch.port().toString().equals(jsonPort)) {
description.appendText("port was " + jsonPort);
return false;
}
} else {
final String jsonPort = instructionJson.get("port").toString();
description.appendText("Unmathcing types ");
description.appendText("instructionToMatch " + instructionToMatch.port().toString());
description.appendText("jsonPort " + jsonPort);
}
return true;
......
......@@ -118,9 +118,8 @@
"example": "OUTPUT"
},
"port": {
"type": "integer",
"format": "int64",
"example": -3
"type": "string",
"example": "CONTROLLER"
}
}
}
......
......@@ -54,9 +54,8 @@
"example": "OUTPUT"
},
"port": {
"type": "integer",
"format": "int64",
"example": -3
"type": "string",
"example": "CONTROLLER"
}
}
}
......
......@@ -55,6 +55,7 @@ import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.rest.resources.CoreWebApplication;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;
......@@ -251,6 +252,10 @@ public class FlowsResourceTest extends ResourceTest {
.andReturn(rules.get(deviceId2)).anyTimes();
}
public FlowsResourceTest() {
super(CoreWebApplication.class);
}
/**
* Sets up the global values for all the tests.
*/
......