REST API changes for client side errors

For the Intent REST APIs, made the following changes:
- GET requests without a specific resource identifier
  return a collection and the response status of OK
- GET requests for a specific resource return the single
  item found and a status of OK on success, and NOT FOUND
  on failure.  For a NOT FOUND, a RestError object is
  returned indicating the error.
- POST requests return the objects they create and a status
  of CREATED if they are successful.  If they fail, a status
  of BAD REQUEST is sent. For a BAD REQUEST, a RestError object is
  returned indicating the error.
- DELETE requests always return the status NO CONTENT and return
  no object.
- standardized method names for REST resource classes:
  GET is retrieve()
  DELETE is remove()
  POST is store()
- removed superfluous checks for null inbound parameters
  on GET operations.

Change-Id: I426ce73a96637dc67f30e1c85e9c200334ff758c
diff --git a/pom.xml b/pom.xml
index 629be48..472f644 100644
--- a/pom.xml
+++ b/pom.xml
@@ -522,6 +522,11 @@
     </dependency>
     <dependency>
       <groupId>org.restlet.jse</groupId>
+      <artifactId>org.restlet.ext.json</artifactId>
+      <version>${restlet.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.jackson</artifactId>
       <version>${restlet.version}</version>
     </dependency>
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java
index c4e2ac4..dd6145d 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java
@@ -1,15 +1,14 @@
 package net.onrc.onos.core.intent.runtime.web;
 
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedList;
-
+import net.onrc.onos.api.rest.RestError;
+import net.onrc.onos.api.rest.RestErrorCodes;
 import net.onrc.onos.core.intent.Intent;
 import net.onrc.onos.core.intent.IntentMap;
 import net.onrc.onos.core.intent.IntentOperation;
 import net.onrc.onos.core.intent.IntentOperationList;
 import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
 import org.restlet.resource.Delete;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
@@ -27,14 +26,16 @@
     /**
      * Gets a single high-level intent.
      *
-     * @return a Collection with the single high-level intent if found,
-     * otherwise null.
+     * @return a Representation of a single high-level intent. If the
+     * intent is not found, return a Representation of a RestError indicating
+     * the problem.
      */
     @Get("json")
-    public Collection<Intent> retrieve() throws IOException {
+    public Representation retrieve() {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
                 getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
-        Collection<Intent> intents = null;
+
+        Representation result;
 
         String intentId = (String) getRequestAttributes().get("intent-id");
         if (intentId == null) {
@@ -48,27 +49,29 @@
         String applnIntentId = APPLN_ID + ":" + intentId;
         Intent intent = intentMap.getIntent(applnIntentId);
         if (intent != null) {
-            intents = new LinkedList<>();
-            intents.add(intent);
+            result = toRepresentation(intent, null);
+        } else {
+            setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+            final RestError notFound =
+                RestError.createRestError(RestErrorCodes.RestErrorCode.INTENT_NOT_FOUND,
+                                          applnIntentId);
+            result = toRepresentation(notFound, null);
         }
 
-        return intents;
+        return result;
     }
 
     /**
      * Deletes a single high-level intent.
      *
-     * @return the status of the operation (TBD).
+     * @return a null Representation.
      */
     @Delete("json")
-    public String store() {
+    public Representation remove() {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
                 getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
 
         String intentId = (String) getRequestAttributes().get("intent-id");
-        if (intentId == null) {
-            return null;        // Missing Intent ID
-        }
 
         //
         // Remove a single high-level Intent: use the Intent ID to find it
@@ -84,6 +87,7 @@
             operations.add(IntentOperation.Operator.REMOVE, intent);
             pathRuntime.executeIntentOperations(operations);
         }
-        return "";      // TODO no reply yet from the purge intents call
+        setStatus(Status.SUCCESS_NO_CONTENT);
+        return null;
     }
 }
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
index 8229e38..d2ffdce 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
@@ -1,8 +1,5 @@
 package net.onrc.onos.core.intent.runtime.web;
 
-import java.io.IOException;
-import java.util.Collection;
-
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.api.intent.ApplicationIntent;
 import net.onrc.onos.api.rest.RestError;
@@ -15,9 +12,9 @@
 import net.onrc.onos.core.intent.ShortestPathIntent;
 import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
 import net.onrc.onos.core.util.Dpid;
-
 import org.codehaus.jackson.map.ObjectMapper;
 import org.restlet.data.Status;
+import org.restlet.representation.Representation;
 import org.restlet.resource.Delete;
 import org.restlet.resource.Get;
 import org.restlet.resource.Post;
@@ -25,6 +22,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.util.Collection;
+
 /**
  * A class to access the high-level intents.
  */
@@ -36,34 +36,35 @@
     /**
      * Gets all high-level intents.
      *
-     * @return a collection with all high-level intents.
+     * @return a Representation for a collection with all of the high-level intents.
      */
     @Get("json")
-    public Collection<Intent> retrieve() throws IOException {
+    public Representation retrieve() throws IOException {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
                 getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
 
         IntentMap intentMap = pathRuntime.getHighLevelIntents();
         Collection<Intent> intents = intentMap.getAllIntents();
 
-        return intents;
+        return toRepresentation(intents, null);
     }
 
     /**
      * Adds a collection of high-level intents.
      *
-     * @return the status of the operation (TBD).
+     * @param jsonIntent JSON representation of the intents to add.
+     * @return a Representation of a collection containing the intents that were
+     *         created.
      */
     @Post("json")
-    public String store(String jsonIntent) throws IOException {
+    public Representation store(String jsonIntent) {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext()
                 .getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
         if (pathRuntime == null) {
             log.warn("Failed to get path calc runtime");
-            return "";
+            return null;
         }
 
-        String reply = "";
         ObjectMapper mapper = new ObjectMapper();
         ApplicationIntent[] addOperations = null;
         try {
@@ -78,7 +79,7 @@
             setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
             final RestError error =
                     RestError.createRestError(RestErrorCodes.RestErrorCode.INTENT_INVALID);
-            return mapper.writeValueAsString(error);
+            return toRepresentation(error, null);
         }
 
         //
@@ -132,16 +133,16 @@
 
         setStatus(Status.SUCCESS_CREATED);
 
-        return reply;
+        return toRepresentation(intentOperations, null);
     }
 
     /**
      * Deletes all high-level intents.
      *
-     * @return the status of the operation (TBD).
+     * @return a null Representation.
      */
     @Delete("json")
-    public String store() {
+    public Representation remove() {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
                 getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
 
@@ -150,6 +151,6 @@
         // TODO: The deletion should use synchronous Java API?
         pathRuntime.purgeIntents();
         setStatus(Status.SUCCESS_NO_CONTENT);
-        return "";      // TODO no reply yet from the purge intents call
+        return null;      // TODO no reply yet from the purge intents call
     }
 }
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java
index 4f5cc8a..1f99152 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java
@@ -1,13 +1,12 @@
 package net.onrc.onos.core.intent.runtime.web;
 
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedList;
-
+import net.onrc.onos.api.rest.RestError;
+import net.onrc.onos.api.rest.RestErrorCodes;
 import net.onrc.onos.core.intent.Intent;
 import net.onrc.onos.core.intent.IntentMap;
 import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
@@ -24,19 +23,17 @@
     /**
      * Gets a single low-level intent.
      *
-     * @return a Collection with the single low-level intent if found,
-     * otherwise null.
+     * @return a Representation of the single low-level intent if found,
+     * otherwise a Representation of a RestError object describing the problem.
      */
     @Get("json")
-    public Collection<Intent> retrieve() throws IOException {
+    public Representation retrieve() {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
                 getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
-        Collection<Intent> intents = null;
+
+        Representation result;
 
         String intentId = (String) getRequestAttributes().get("intent-id");
-        if (intentId == null) {
-            return null;        // Missing Intent ID
-        }
 
         //
         // Get a single low-level Intent: use the Intent ID to find it
@@ -45,10 +42,15 @@
         String applnIntentId = APPLN_ID + ":" + intentId;
         Intent intent = intentMap.getIntent(applnIntentId);
         if (intent != null) {
-            intents = new LinkedList<>();
-            intents.add(intent);
+            result = toRepresentation(intent, null);
+        } else {
+            setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+            final RestError notFound =
+                    RestError.createRestError(RestErrorCodes.RestErrorCode.INTENT_NOT_FOUND,
+                            applnIntentId);
+            result = toRepresentation(notFound, null);
         }
 
-        return intents;
+        return result;
     }
 }
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java
index bf0b527..7a15c26 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java
@@ -1,17 +1,16 @@
 package net.onrc.onos.core.intent.runtime.web;
 
-import java.io.IOException;
-import java.util.Collection;
-
 import net.onrc.onos.core.intent.Intent;
 import net.onrc.onos.core.intent.IntentMap;
 import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-
+import org.restlet.representation.Representation;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collection;
+
 /**
  * A class to access the low-level intents.
  */
@@ -21,10 +20,10 @@
     /**
      * Gets all low-level intents.
      *
-     * @return a collection of all low-leve intents.
+     * @return a Representation of a collection of all of the low-level intents.
      */
     @Get("json")
-    public Collection<Intent> retrieve() throws IOException {
+    public Representation retrieve() {
         IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
                 getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
 
@@ -34,6 +33,6 @@
         IntentMap intentMap = pathRuntime.getPathIntents();
         Collection<Intent> intents = intentMap.getAllIntents();
 
-        return intents;
+        return toRepresentation(intents, null);
     }
 }