Add JSON decoders for Host and HostLocation
- HostsWebResource will use the Host codec in parsing JSON for create-host requests
Change-Id: If51bf3433a4ab45889a94a6d11bbd3db6b96d074
(cherry picked from commit 46d2462e4e49855b0d533035250776589fd05d88)
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
index d2890a4..dc6538e 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
@@ -15,57 +15,136 @@
*/
package org.onosproject.codec.impl;
-import org.onlab.packet.IpAddress;
-import org.onosproject.codec.CodecContext;
-import org.onosproject.codec.JsonCodec;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostLocation;
-
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.EthType;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
/**
- * Host JSON codec.
+ * JSON codec for Host class.
*/
public final class HostCodec extends AnnotatedCodec<Host> {
+ // JSON field names
+ public static final String HOST_ID = "id";
+ public static final String MAC = "mac";
+ public static final String VLAN = "vlan";
+ public static final String INNER_VLAN = "innerVlan";
+ public static final String OUTER_TPID = "outerTpid";
+ public static final String IS_CONFIGURED = "configured";
+ public static final String IS_SUSPENDED = "suspended";
+ public static final String IP_ADDRESSES = "ipAddresses";
+ public static final String HOST_LOCATIONS = "locations";
+ public static final String AUX_LOCATIONS = "auxLocations";
+
+ private static final String NULL_OBJECT_MSG = "Host cannot be null";
+ private static final String MISSING_MEMBER_MESSAGE = " member is required in Host";
+
@Override
public ObjectNode encode(Host host, CodecContext context) {
- checkNotNull(host, "Host cannot be null");
+ checkNotNull(host, NULL_OBJECT_MSG);
+
final JsonCodec<HostLocation> locationCodec =
context.codec(HostLocation.class);
+ // keep fields in string for compatibility
final ObjectNode result = context.mapper().createObjectNode()
- .put("id", host.id().toString())
- .put("mac", host.mac().toString())
- .put("vlan", host.vlan().toString())
- .put("innerVlan", host.innerVlan().toString())
- .put("outerTpid", host.tpid().toString())
- .put("configured", host.configured());
+ .put(HOST_ID, host.id().toString())
+ .put(MAC, host.mac().toString())
+ .put(VLAN, host.vlan().toString())
+ .put(INNER_VLAN, host.innerVlan().toString())
+ // use a 4-digit hex string in coding an ethernet type
+ .put(OUTER_TPID, String.format("0x%04x", host.tpid().toShort()))
+ .put(IS_CONFIGURED, host.configured())
+ .put(IS_SUSPENDED, host.suspended());
- final ArrayNode jsonIpAddresses = result.putArray("ipAddresses");
+ final ArrayNode jsonIpAddresses = result.putArray(IP_ADDRESSES);
for (final IpAddress ipAddress : host.ipAddresses()) {
jsonIpAddresses.add(ipAddress.toString());
}
- result.set("ipAddresses", jsonIpAddresses);
+ result.set(IP_ADDRESSES, jsonIpAddresses);
- final ArrayNode jsonLocations = result.putArray("locations");
+ final ArrayNode jsonLocations = result.putArray(HOST_LOCATIONS);
for (final HostLocation location : host.locations()) {
jsonLocations.add(locationCodec.encode(location, context));
}
- result.set("locations", jsonLocations);
+ result.set(HOST_LOCATIONS, jsonLocations);
if (host.auxLocations() != null) {
- final ArrayNode jsonAuxLocations = result.putArray("auxLocations");
+ final ArrayNode jsonAuxLocations = result.putArray(AUX_LOCATIONS);
for (final HostLocation auxLocation : host.auxLocations()) {
jsonAuxLocations.add(locationCodec.encode(auxLocation, context));
}
- result.set("auxLocations", jsonAuxLocations);
+ result.set(AUX_LOCATIONS, jsonAuxLocations);
}
return annotate(result, host, context);
}
-}
+ @Override
+ public Host decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+ MacAddress mac = MacAddress.valueOf(nullIsIllegal(
+ json.get(MAC), MAC + MISSING_MEMBER_MESSAGE).asText());
+ VlanId vlanId = VlanId.vlanId(nullIsIllegal(
+ json.get(VLAN), VLAN + MISSING_MEMBER_MESSAGE).asText());
+ HostId id = HostId.hostId(mac, vlanId);
+
+ ArrayNode locationNodes = nullIsIllegal(
+ (ArrayNode) json.get(HOST_LOCATIONS), HOST_LOCATIONS + MISSING_MEMBER_MESSAGE);
+ Set<HostLocation> hostLocations =
+ context.codec(HostLocation.class).decode(locationNodes, context)
+ .stream().collect(Collectors.toSet());
+
+ ArrayNode ipNodes = nullIsIllegal(
+ (ArrayNode) json.get(IP_ADDRESSES), IP_ADDRESSES + MISSING_MEMBER_MESSAGE);
+ Set<IpAddress> ips = new HashSet<>();
+ ipNodes.forEach(ipNode -> {
+ ips.add(IpAddress.valueOf(ipNode.asText()));
+ });
+
+ // check optional fields
+ JsonNode innerVlanIdNode = json.get(INNER_VLAN);
+ VlanId innerVlanId = (null == innerVlanIdNode) ? VlanId.NONE :
+ VlanId.vlanId(innerVlanIdNode.asText());
+ JsonNode outerTpidNode = json.get(OUTER_TPID);
+ EthType outerTpid = (null == outerTpidNode) ? EthType.EtherType.UNKNOWN.ethType() :
+ EthType.EtherType.lookup((short) (Integer.decode(outerTpidNode.asText()) & 0xFFFF)).ethType();
+ JsonNode configuredNode = json.get(IS_CONFIGURED);
+ boolean configured = (null == configuredNode) ? false : configuredNode.asBoolean();
+ JsonNode suspendedNode = json.get(IS_SUSPENDED);
+ boolean suspended = (null == suspendedNode) ? false : suspendedNode.asBoolean();
+
+ ArrayNode auxLocationNodes = (ArrayNode) json.get(AUX_LOCATIONS);
+ Set<HostLocation> auxHostLocations = (null == auxLocationNodes) ? null :
+ context.codec(HostLocation.class).decode(auxLocationNodes, context)
+ .stream().collect(Collectors.toSet());
+
+ Annotations annotations = extractAnnotations(json, context);
+
+ return new DefaultHost(ProviderId.NONE, id, mac, vlanId,
+ hostLocations, auxHostLocations, ips, innerVlanId,
+ outerTpid, configured, suspended, annotations);
+ }
+
+}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java
index efcd133..da4405d 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java
@@ -17,23 +17,45 @@
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.HostLocation;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.net.PortNumber;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
/**
- * Host JSON codec.
+ * HostLocation JSON codec.
*/
public final class HostLocationCodec extends JsonCodec<HostLocation> {
+ public static final String ELEMENT_ID = "elementId";
+ public static final String PORT = "port";
+
+ private static final String MISSING_MEMBER_MESSAGE =
+ " member is required in HostLocation";
+
@Override
public ObjectNode encode(HostLocation hostLocation, CodecContext context) {
checkNotNull(hostLocation, "Host location cannot be null");
return context.mapper().createObjectNode()
- .put("elementId", hostLocation.elementId().toString())
- .put("port", hostLocation.port().toString());
+ .put(ELEMENT_ID, hostLocation.elementId().toString())
+ .put(PORT, hostLocation.port().toString());
}
+ @Override
+ public HostLocation decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ DeviceId deviceId = DeviceId.deviceId(nullIsIllegal(
+ json.get(ELEMENT_ID), ELEMENT_ID + MISSING_MEMBER_MESSAGE).asText());
+ PortNumber portNumber = PortNumber.portNumber(nullIsIllegal(
+ json.get(PORT), PORT + MISSING_MEMBER_MESSAGE).asText());
+
+ return new HostLocation(deviceId, portNumber, 0);
+ }
}