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";
+    }
+
+}
diff --git a/src/test/java/net/onrc/onos/core/flowmanager/web/FlowResourceTest.java b/src/test/java/net/onrc/onos/core/flowmanager/web/FlowResourceTest.java
new file mode 100644
index 0000000..37f6f5a
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/flowmanager/web/FlowResourceTest.java
@@ -0,0 +1,124 @@
+package net.onrc.onos.core.flowmanager.web;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.api.flowmanager.Flow;
+import net.onrc.onos.api.flowmanager.FlowId;
+import net.onrc.onos.api.flowmanager.FlowLink;
+import net.onrc.onos.api.flowmanager.FlowManagerService;
+import net.onrc.onos.api.flowmanager.OpticalPathFlow;
+import net.onrc.onos.api.flowmanager.PacketPathFlow;
+import net.onrc.onos.api.flowmanager.Path;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
+import net.onrc.onos.core.matchaction.action.ModifyLambdaAction;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
+import net.onrc.onos.core.util.PortNumber;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.representation.Representation;
+
+/**
+ * Tests for the {@link FlowResource} REST handler.
+ */
+public class FlowResourceTest {
+    FlowResource flowResource;
+
+    /**
+     * Set up the FlowResource for the test.
+     */
+    @Before
+    public void setUp() {
+        // Create some flow data
+        Set<Flow> flowSet = createFlows();
+
+        // Create a mock flow manager service that will return the flows
+        FlowManagerService flowManager = createMock(FlowManagerService.class);
+        expect(flowManager.getFlows()).andReturn(flowSet);
+        replay(flowManager);
+
+        // Inject the flow manager service into a Restlet context
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put(FlowManagerService.class.getCanonicalName(), flowManager);
+        Context context = new Context();
+        context.setAttributes(attributes);
+
+        // Create a FlowResource and initialize with the context
+        flowResource = new FlowResource();
+        flowResource.init(context, new Request(), null);
+    }
+
+    /**
+     * Creates some flow data that the REST handler can retrieve.
+     * The data is arbitrary because it is never verified during the test.
+     *
+     * @return a set of dummy Flow objects for the test
+     */
+    private Set<Flow> createFlows() {
+        Set<Flow> flowSet = new HashSet<>();
+
+        PacketMatch match = new PacketMatchBuilder().setDstTcpPort((short) 1).build();
+
+        List<FlowLink> links = new ArrayList<>();
+        links.add(new FlowLink(new SwitchPort(1L, 2L), new SwitchPort(2L, 1L)));
+        links.add(new FlowLink(new SwitchPort(2L, 2L), new SwitchPort(3L, 1L)));
+
+        Path path = new Path(links);
+
+        PacketPathFlow packetFlow = new PacketPathFlow(new FlowId(1L),
+                match, PortNumber.uint32(1), path,
+                Collections.<Action>singletonList(new ModifyDstMacAction(MACAddress.valueOf(4L))),
+                0, 0);
+
+        OpticalPathFlow opticalFlow = new OpticalPathFlow(new FlowId(2L),
+                PortNumber.uint32(3), path,
+                Collections.<Action>singletonList(new ModifyLambdaAction(2)), 4);
+
+        flowSet.add(packetFlow);
+        flowSet.add(opticalFlow);
+
+        return flowSet;
+    }
+
+    /**
+     * Tests the handler method that retrieves all flow resources.
+     *
+     * @throws IOException if there's an error serializing the representation
+     */
+    @Test
+    public void testRetrieve() throws IOException {
+        Representation rep = flowResource.retrieve();
+
+        StringWriter writer = new StringWriter();
+
+        rep.write(writer);
+        String output = writer.toString();
+
+        System.out.println(writer);
+
+        assertNotNull(output);
+        // Output should be a JSON array of JSON objects
+        assertTrue(output.startsWith("[{"));
+    }
+
+}
diff --git a/src/test/java/net/onrc/onos/core/matchaction/web/MatchActionResourceTest.java b/src/test/java/net/onrc/onos/core/matchaction/web/MatchActionResourceTest.java
new file mode 100644
index 0000000..6bea4ff
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/matchaction/web/MatchActionResourceTest.java
@@ -0,0 +1,113 @@
+package net.onrc.onos.core.matchaction.web;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.core.matchaction.MatchAction;
+import net.onrc.onos.core.matchaction.MatchActionId;
+import net.onrc.onos.core.matchaction.MatchActionService;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
+import net.onrc.onos.core.util.IPv4;
+import net.onrc.onos.core.util.PortNumber;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.representation.Representation;
+
+/**
+ * Tests for the {@link MatchActionResource} REST handler.
+ */
+public class MatchActionResourceTest {
+
+    private MatchActionResource matchActionResource;
+
+    /**
+     * Set up the MatchActionResource for the test.
+     */
+    @Before
+    public void setUp() {
+        // Create some match-action data
+        Set<MatchAction> matchActionSet = createMatchActions();
+
+        // Create a mock match-action service that will return the match-actions
+        MatchActionService matchActionService = createMock(MatchActionService.class);
+        expect(matchActionService.getMatchActions()).andReturn(matchActionSet).anyTimes();
+        replay(matchActionService);
+
+        // Inject the match-action service into a Restlet context
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put(MatchActionService.class.getCanonicalName(), matchActionService);
+        Context context = new Context();
+        context.setAttributes(attributes);
+
+        // Create a MatchActionResource and initialize with the context
+        matchActionResource = new MatchActionResource();
+        matchActionResource.init(context, new Request(), null);
+    }
+
+    /**
+     * Creates some match-action data that the REST handler can retrieve.
+     * The data is arbitrary because it is never verified during the test.
+     *
+     * @return a set of dummy MatchAction objects for the test
+     */
+    private Set<MatchAction> createMatchActions() {
+        Set<MatchAction> matchActionSet = new HashSet<>();
+
+        Match match = new PacketMatchBuilder().setDstTcpPort((short) 1)
+                .setDstIp(new IPv4(5)).build();
+
+        List<Action> actions = new ArrayList<>();
+        actions.add(new ModifyDstMacAction(MACAddress.valueOf(10L)));
+        actions.add(new OutputAction(PortNumber.uint32(4)));
+
+        MatchAction ma = new MatchAction(new MatchActionId(1L), new SwitchPort(1L, 1L), match,
+                actions);
+
+        matchActionSet.add(ma);
+
+        return matchActionSet;
+    }
+
+    /**
+     * Tests the handler method that retrieves all match-action resources.
+     *
+     * @throws IOException if there's an error serializing the representation
+     */
+    @Test
+    public void testRetrieve() throws IOException {
+        Representation rep = matchActionResource.retrieve();
+
+        StringWriter writer = new StringWriter();
+
+        rep.write(writer);
+        String output = writer.toString();
+
+        System.out.println(output);
+
+        assertNotNull(output);
+        // Output should be a JSON array of JSON objects
+        assertTrue(output.startsWith("[{"));
+    }
+
+}
diff --git a/src/test/java/net/onrc/onos/core/newintent/web/IntentResourceTest.java b/src/test/java/net/onrc/onos/core/newintent/web/IntentResourceTest.java
new file mode 100644
index 0000000..74ba5c1
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/newintent/web/IntentResourceTest.java
@@ -0,0 +1,115 @@
+package net.onrc.onos.core.newintent.web;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentId;
+import net.onrc.onos.api.newintent.IntentService;
+import net.onrc.onos.api.newintent.MultiPointToSinglePointIntent;
+import net.onrc.onos.api.newintent.PointToPointIntent;
+import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.representation.Representation;
+
+/**
+ * Tests for the {@link IntentResource} REST handler.
+ */
+public class IntentResourceTest {
+    private IntentResource intentResource;
+
+    /**
+     * Set up the IntentResource for the test.
+     */
+    @Before
+    public void setUp() {
+        // Create some intent data
+        Set<Intent> intentSet = createIntents();
+
+        // Create a mock intent service that will return the intents
+        IntentService intentService = createMock(IntentService.class);
+        expect(intentService.getIntents()).andReturn(intentSet).anyTimes();
+        replay(intentService);
+
+        // Inject the intent service into a Restlet context
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put(IntentService.class.getCanonicalName(), intentService);
+        Context context = new Context();
+        context.setAttributes(attributes);
+
+        // Create an IntentResource and initialize with the context
+        intentResource = new IntentResource();
+        intentResource.init(context, new Request(), null);
+    }
+
+    /**
+     * Creates some intent data that the REST handler can retrieve.
+     * The data is arbitrary because it is never verified during the test.
+     *
+     * @return a set of dummy Intent objects for the test
+     */
+    private Set<Intent> createIntents() {
+        Set<Intent> intentSet = new HashSet<>();
+
+        Match match = new PacketMatchBuilder().setDstTcpPort((short) 1).build();
+
+        Intent pointToPointIntent = new PointToPointIntent(new IntentId(1L), match,
+                new ModifyDstMacAction(MACAddress.valueOf(1L)),
+                new SwitchPort(1L, 1L),
+                new SwitchPort(2L, 2L));
+
+        Set<SwitchPort> inPorts = new HashSet<>();
+        inPorts.add(new SwitchPort(3L, 3L));
+        inPorts.add(new SwitchPort(4L, 4L));
+
+        Intent multiPointToPointIntent = new MultiPointToSinglePointIntent(
+                new IntentId(2L), match,
+                new ModifyDstMacAction(MACAddress.valueOf(2L)),
+                inPorts, new SwitchPort(5L, 5L));
+
+        intentSet.add(pointToPointIntent);
+        intentSet.add(multiPointToPointIntent);
+
+        return intentSet;
+    }
+
+    /**
+     * Tests the handler method that retrieves all intent resources.
+     *
+     * @throws IOException if there's an error serializing the representation
+     */
+    @Test
+    public void testGetAllIntents() throws IOException {
+        Representation rep = intentResource.retrieve();
+
+        StringWriter writer = new StringWriter();
+
+        rep.write(writer);
+        String output = writer.toString();
+
+        System.out.println(output);
+
+        assertNotNull(output);
+        // Output should be a JSON array of JSON objects
+        assertTrue(output.startsWith("[{"));
+    }
+
+}