Getter REST APIs for Intents, FlowManager, and MatchAction.

Resource and Routable classes are implemented but will need to be registered
with the REST server when the module implementations are in place.

Right now they use default JSON serializers for everything apart from the ID
classes, which couldn't be default serialized. We can write custom serializers
for the objects if the need arises.

ONOS-1878
ONOS-1876
ONOS-1877

Change-Id: I48df3532afcf1e8bec104a52d58e23a6af4cffbe
diff --git a/src/main/java/net/floodlightcontroller/restserver/CustomSerializerHelper.java b/src/main/java/net/floodlightcontroller/restserver/CustomSerializerHelper.java
new file mode 100644
index 0000000..9810563
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/restserver/CustomSerializerHelper.java
@@ -0,0 +1,66 @@
+package net.floodlightcontroller.restserver;
+
+import org.codehaus.jackson.Version;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.module.SimpleModule;
+import org.codehaus.jackson.map.ser.CustomSerializerFactory;
+import org.restlet.ext.jackson.JacksonRepresentation;
+import org.restlet.representation.Representation;
+
+/**
+ * Helper class used to dynamically override the default serializers used for
+ * JSON serialization.
+ * <p/>
+ * Serializers can be added to the helper class at runtime using
+ * {@link #addSerializer(Class, JsonSerializer)}. The serializers contained by
+ * the helper class can then be added to a JacksonRepresentation prior to
+ * serializing it using {@link #applySerializers(JacksonRepresentation)}.
+ * <p/>
+ * This class enables the use of custom serializers for Java objects without
+ * having to hardcode the mapping of class to serializer using
+ * annotations on the class. Any serialization annotations on the class will be
+ * overridden by the serializers used here, so different serializers can be
+ * used on the class in different contexts.
+ */
+public class CustomSerializerHelper {
+    private final ObjectMapper mapper;
+    private final SimpleModule customSerializerModule;
+    private CustomSerializerFactory sf;
+
+    /**
+     * Constructor.
+     */
+    public CustomSerializerHelper() {
+        mapper = new ObjectMapper();
+        customSerializerModule = new SimpleModule("custom-serializers", new Version(1, 0, 0, null));
+        mapper.registerModule(customSerializerModule);
+        sf =  new CustomSerializerFactory();
+    }
+
+    /**
+     * Adds a serializer to the set of serializers that will be used for JSON
+     * serialization.
+     *
+     * @param serializer the serializer to add
+     */
+    public <T> void addSerializer(Class<T> clazz, JsonSerializer<T> serializer) {
+        customSerializerModule.addSerializer(serializer);
+        sf.addGenericMapping(clazz, serializer);
+    }
+
+    /**
+     * Applies the list of serializers to the JacksonRepresentation so they
+     * will be used when the object in the representation is serialized
+     *
+     * @param jacksonRepresentation the representation to apply the serializers
+     * to
+     * @return a representation with the custom serializers applied
+     */
+    public Representation applySerializers(JacksonRepresentation<?> jacksonRepresentation) {
+        mapper.registerModule(customSerializerModule);
+        jacksonRepresentation.setObjectMapper(mapper);
+        mapper.setSerializerFactory(sf);
+        return jacksonRepresentation;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/flowmanager/web/FlowManagerWebRoutable.java b/src/main/java/net/onrc/onos/core/flowmanager/web/FlowManagerWebRoutable.java
new file mode 100644
index 0000000..e41b023
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/flowmanager/web/FlowManagerWebRoutable.java
@@ -0,0 +1,26 @@
+package net.onrc.onos.core.flowmanager.web;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+/**
+ * Routable class for flow REST API URLs.
+ */
+public class FlowManagerWebRoutable implements RestletRoutable {
+
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router();
+        router.attach("", FlowResource.class);
+        return router;
+    }
+
+    @Override
+    public String basePath() {
+        return "/wm/onos/flow";
+    }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/flowmanager/web/FlowResource.java b/src/main/java/net/onrc/onos/core/flowmanager/web/FlowResource.java
new file mode 100644
index 0000000..4079687
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/flowmanager/web/FlowResource.java
@@ -0,0 +1,61 @@
+package net.onrc.onos.core.flowmanager.web;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import net.floodlightcontroller.restserver.CustomSerializerHelper;
+import net.onrc.onos.api.flowmanager.Flow;
+import net.onrc.onos.api.flowmanager.FlowId;
+import net.onrc.onos.api.flowmanager.FlowManagerService;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+import org.restlet.ext.jackson.JacksonRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+/**
+ * Handles REST requests for flow resources.
+ */
+public class FlowResource extends ServerResource {
+
+    private final CustomSerializerHelper flowSerializers;
+
+    /**
+     * Constructs a FlowResource.
+     * <p/>
+     * A custom serializer for {@link FlowId} is automatically registered,
+     * because FlowId can't be serialized by default.
+     */
+    public FlowResource() {
+        flowSerializers = new CustomSerializerHelper();
+        flowSerializers.addSerializer(FlowId.class, new SerializerBase<FlowId>(FlowId.class) {
+            @Override
+            public void serialize(FlowId flowId, JsonGenerator jgen,
+                    SerializerProvider provider) throws IOException,
+                    JsonGenerationException {
+                jgen.writeString(flowId.toString());
+            }
+        });
+    }
+
+    /**
+     * Handles REST requests for all flow resources.
+     *
+     * @return JSON-serializable Representation of all flow resources
+     */
+    @Get("json")
+    public Representation retrieve() {
+        FlowManagerService flowService =
+                (FlowManagerService) getContext().getAttributes()
+                    .get(FlowManagerService.class.getCanonicalName());
+
+        Collection<Flow> flows = flowService.getFlows();
+
+        return flowSerializers.applySerializers(
+                (JacksonRepresentation<?>) toRepresentation(flows, null));
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/matchaction/web/MatchActionResource.java b/src/main/java/net/onrc/onos/core/matchaction/web/MatchActionResource.java
new file mode 100644
index 0000000..037ee88
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/matchaction/web/MatchActionResource.java
@@ -0,0 +1,61 @@
+package net.onrc.onos.core.matchaction.web;
+
+import java.io.IOException;
+import java.util.Set;
+
+import net.floodlightcontroller.restserver.CustomSerializerHelper;
+import net.onrc.onos.core.matchaction.MatchAction;
+import net.onrc.onos.core.matchaction.MatchActionId;
+import net.onrc.onos.core.matchaction.MatchActionService;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+import org.restlet.ext.jackson.JacksonRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+/**
+ * Handles REST requests for match-action resources.
+ */
+public class MatchActionResource extends ServerResource {
+
+    CustomSerializerHelper matchActionSerializers;
+
+    /**
+     * Constructs a MatchActionResource.
+     * <p/>
+     * A custom serializer for {@link MatchActionId} is automatically
+     * registered, because MatchActionId can't be serialized by default.
+     */
+    public MatchActionResource() {
+        matchActionSerializers = new CustomSerializerHelper();
+        matchActionSerializers.addSerializer(MatchActionId.class,
+                new SerializerBase<MatchActionId>(MatchActionId.class) {
+            @Override
+            public void serialize(MatchActionId id, JsonGenerator jGen, SerializerProvider sp)
+                    throws IOException, JsonProcessingException {
+                jGen.writeString(id.toString());
+            }
+        });
+    }
+
+    /**
+     * Handles REST requests for all match-action resources.
+     *
+     * @return JSON-serializable Representation of all match-action resources
+     */
+    @Get("json")
+    public Representation retrieve() {
+        MatchActionService matchActionService =
+                (MatchActionService) getContext().getAttributes()
+                    .get(MatchActionService.class.getCanonicalName());
+
+        Set<MatchAction> matchActions = matchActionService.getMatchActions();
+
+        return matchActionSerializers.applySerializers(
+                (JacksonRepresentation<?>) toRepresentation(matchActions, null));
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/matchaction/web/MatchActionWebRoutable.java b/src/main/java/net/onrc/onos/core/matchaction/web/MatchActionWebRoutable.java
new file mode 100644
index 0000000..638b0ad
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/matchaction/web/MatchActionWebRoutable.java
@@ -0,0 +1,26 @@
+package net.onrc.onos.core.matchaction.web;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+/**
+ * Routable class for match-action REST API URLs.
+ */
+public class MatchActionWebRoutable implements RestletRoutable {
+
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router();
+        router.attach("", MatchActionResource.class);
+        return router;
+    }
+
+    @Override
+    public String basePath() {
+        return "/wm/onos/matchaction";
+    }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/web/IntentResource.java b/src/main/java/net/onrc/onos/core/newintent/web/IntentResource.java
new file mode 100644
index 0000000..4230298
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/web/IntentResource.java
@@ -0,0 +1,62 @@
+package net.onrc.onos.core.newintent.web;
+
+import java.io.IOException;
+import java.util.Set;
+
+import net.floodlightcontroller.restserver.CustomSerializerHelper;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentId;
+import net.onrc.onos.api.newintent.IntentService;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+import org.restlet.ext.jackson.JacksonRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+/**
+ * Handles REST requests for intent resources.
+ */
+public class IntentResource extends ServerResource {
+
+    CustomSerializerHelper intentSerializers;
+
+    /**
+     * Constructs an IntentResource.
+     * <p/>
+     * A custom serializer for {@link IntentId} is automatically registered,
+     * because IntentId can't be serialized by default.
+     */
+    public IntentResource() {
+        intentSerializers = new CustomSerializerHelper();
+        intentSerializers.addSerializer(IntentId.class,
+            new SerializerBase<IntentId>(IntentId.class) {
+                @Override
+                public void serialize(IntentId id, JsonGenerator jGen,
+                        SerializerProvider sp) throws IOException,
+                        JsonProcessingException {
+                    jGen.writeString(id.toString());
+                }
+            });
+    }
+
+    /**
+     * Handles REST requests for all intent resources.
+     *
+     * @return JSON-serializable Representation of all intent resources
+     */
+    @Get("json")
+    public Representation retrieve() {
+        IntentService intentService =
+                (IntentService) getContext().getAttributes()
+                    .get(IntentService.class.getCanonicalName());
+
+        Set<Intent> intents = intentService.getIntents();
+
+        return intentSerializers.applySerializers(
+                (JacksonRepresentation<?>) toRepresentation(intents, null));
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/web/IntentWebRoutable.java b/src/main/java/net/onrc/onos/core/newintent/web/IntentWebRoutable.java
new file mode 100644
index 0000000..fb408bc
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/web/IntentWebRoutable.java
@@ -0,0 +1,26 @@
+package net.onrc.onos.core.newintent.web;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+/**
+ * Routable class for intent REST API URLs.
+ */
+public class IntentWebRoutable implements RestletRoutable {
+
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router(context);
+        router.attach("", IntentResource.class);
+        return router;
+    }
+
+    @Override
+    public String basePath() {
+        return "/wm/onos/newintent";
+    }
+
+}