Add support to decode Device, Port, Link JSON.

- Device, Port, Link can now be encoded and decoded back to Java Object,
  which will be Object#equals to the original.
- Modified DeviceServiceAdapter to be null-safe when possible
- Modified JSON assertion/matcher not to check for exact number of attributes

Change-Id: I7cf02e2254cf17f6265fb15847912519e564b14f
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java
new file mode 100644
index 0000000..c7196e8
--- /dev/null
+++ b/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.codec.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable;
+
+import org.junit.Test;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.DeviceServiceAdapter;
+
+/**
+ * Unit test for DeviceCodec.
+ */
+public class DeviceCodecTest {
+
+    private Device device = new DefaultDevice(JsonCodecUtils.PID,
+                                              JsonCodecUtils.DID1,
+                                              Device.Type.SWITCH,
+                                              JsonCodecUtils.MFR,
+                                              JsonCodecUtils.HW,
+                                              JsonCodecUtils.SW1,
+                                              JsonCodecUtils.SN,
+                                              JsonCodecUtils.CID,
+                                              JsonCodecUtils.A1);
+
+
+
+    @Test
+    public void deviceCodecTest() {
+        final MockCodecContext context = new MockCodecContext();
+        context.registerService(DeviceService.class, new DeviceServiceAdapter());
+        final JsonCodec<Device> codec = context.codec(Device.class);
+        assertThat(codec, is(notNullValue()));
+        final Device pojoIn = device;
+
+        assertJsonEncodable(context, codec, pojoIn);
+    }
+
+}
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java b/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java
new file mode 100644
index 0000000..67c2f47
--- /dev/null
+++ b/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.codec.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertEquals;
+import static org.onosproject.net.DeviceId.deviceId;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.provider.ProviderId;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * JsonCodec test utilities.
+ */
+public abstract class JsonCodecUtils {
+
+    /**
+     * Checks if given Object can be encoded to JSON and back.
+     *
+     * @param context CodecContext
+     * @param codec JsonCodec
+     * @param pojoIn Java Object to encode.
+     *               Object is expected to have #equals implemented.
+     */
+    public static <T> void assertJsonEncodable(final CodecContext context,
+                            final JsonCodec<T> codec,
+                            final T pojoIn) {
+        final ObjectNode json = codec.encode(pojoIn, context);
+
+        assertThat(json, is(notNullValue()));
+
+        final T pojoOut = codec.decode(json, context);
+        assertThat(pojoOut, is(notNullValue()));
+
+        assertEquals(pojoIn, pojoOut);
+    }
+
+    static final ProviderId PID = new ProviderId("of", "foo");
+    static final ProviderId PIDA = new ProviderId("of", "bar", true);
+    static final DeviceId DID1 = deviceId("of:foo");
+    static final DeviceId DID2 = deviceId("of:bar");
+    static final String MFR = "whitebox";
+    static final String HW = "1.1.x";
+    static final String SW1 = "3.8.1";
+    static final String SW2 = "3.9.5";
+    static final String SN = "43311-12345";
+    static final ChassisId CID = new ChassisId();
+    static final PortNumber P1 = PortNumber.portNumber(1);
+    static final PortNumber P2 = PortNumber.portNumber(2);
+    static final PortNumber P3 = PortNumber.portNumber(3);
+    static final SparseAnnotations A1 = DefaultAnnotations.builder()
+                                        .set("A1", "a1")
+                                        .set("B1", "b1")
+                                        .build();
+    static final ConnectPoint CP1 = new ConnectPoint(DID1, P1);
+    static final ConnectPoint CP2 = new ConnectPoint(DID2, P2);
+
+}
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java
new file mode 100644
index 0000000..c44b0eb
--- /dev/null
+++ b/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.codec.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable;
+
+import org.junit.Test;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.Link;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.DeviceServiceAdapter;
+
+/**
+ * Unit test for LinkCodec.
+ */
+public class LinkCodecTest {
+
+    private final Link link = new DefaultLink(JsonCodecUtils.PID,
+                                              JsonCodecUtils.CP1,
+                                              JsonCodecUtils.CP2,
+                                              Link.Type.DIRECT,
+                                              Link.State.ACTIVE,
+                                              false,
+                                              JsonCodecUtils.A1);
+
+    @Test
+    public void linkCodecTest() {
+        final MockCodecContext context = new MockCodecContext();
+        context.registerService(DeviceService.class, new DeviceServiceAdapter());
+        final JsonCodec<Link> codec = context.codec(Link.class);
+        assertThat(codec, is(notNullValue()));
+        final Link pojoIn = link;
+
+        assertJsonEncodable(context, codec, pojoIn);
+    }
+}
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java b/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java
index 25a4fbb..4c869c1 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java
@@ -15,6 +15,9 @@
  */
 package org.onosproject.codec.impl;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
 
@@ -25,8 +28,9 @@
  */
 public class MockCodecContext implements CodecContext {
 
-    private ObjectMapper mapper = new ObjectMapper();
-    private CodecManager manager = new CodecManager();
+    private final ObjectMapper mapper = new ObjectMapper();
+    private final CodecManager manager = new CodecManager();
+    private final Map<Class<? extends Object>, Object> services = new HashMap<>();
 
     /**
      * Constructs a new mock codec context.
@@ -46,9 +50,15 @@
         return manager.getCodec(entityClass);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public <T> T get(Class<T> serviceClass) {
-        return null;
+        return (T) services.get(serviceClass);
+    }
+
+    // for registering mock services
+    public <T> void registerService(Class<T> serviceClass, T impl) {
+        services.put(serviceClass, impl);
     }
 
 }
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java
new file mode 100644
index 0000000..f3f7d92
--- /dev/null
+++ b/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.codec.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable;
+
+import org.junit.Test;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.DeviceServiceAdapter;
+
+/**
+ * Unit test for PortCodec.
+ */
+public class PortCodecTest {
+
+
+
+    private final Device device = new DefaultDevice(JsonCodecUtils.PID,
+                                              JsonCodecUtils.DID1,
+                                              Device.Type.SWITCH,
+                                              JsonCodecUtils.MFR,
+                                              JsonCodecUtils.HW,
+                                              JsonCodecUtils.SW1,
+                                              JsonCodecUtils.SN,
+                                              JsonCodecUtils.CID,
+                                              JsonCodecUtils.A1);
+
+    private final Port port = new DefaultPort(device,
+                                              JsonCodecUtils.P1,
+                                              true,
+                                              JsonCodecUtils.A1);
+
+    @Test
+    public void portCodecTest() {
+        final MockCodecContext context = new MockCodecContext();
+        context.registerService(DeviceService.class, new DeviceServiceAdapter());
+        final JsonCodec<Port> codec = context.codec(Port.class);
+        assertThat(codec, is(notNullValue()));
+        final Port pojoIn = port;
+
+        assertJsonEncodable(context, codec, pojoIn);
+    }
+
+}