WIP: Refactoring the Intent REST API.
NOTE: All changes are Work-in-Progress, and they are in the process
of being actively updated and refactored.

 * The new implementation is in onos/core/intent/runtime/web
   The old implementation in the onos/core/datagrid/web is kept until
   the refactoring is completed.

 * The new REST API base path is /wm/onos/intent

 * The initial set of (new) APIs is the following:
   - /wm/onos/intent/high
     GET all high-level intent
     POST (create) a collection of high-level intents
     DELETE all intents

   - /wm/onos/intent/high/{intent-id}
     GET a high-level intent object
     DELETE a high-level intent object

   - /wm/onos/intent/low
     GET all low-level intents

   - /wm/onos/intent/low/{intent-id}
     GET a low-level intent object

   - /wm/onos/intent/path/switch/{src-dpid}/shortest-path/{dst-dpid}
     GET a Shortest Path between two Switch DPIDs

  * The Application-Level Intent object is specified in class
    onos/api/intent/ApplicationIntent.java

TODO (list incomplete):
 - Return the appropriate REST codes and return values for each REST operation
 - Add the appropriate Java APIs so each REST call would make a single
   Java call.
 - If necessary, rename API class ApplicationIntent to something more
   appropriate, and use it in the Java API.
 - Re-think/refactor the ApplicationIntent so it becomes a more solid base for
   all (high-level) intents.
 - The corresponding Java APIs for each REST call should be synchronous
   (for some definition of the expected operation outcome).
 - Implement intent/intents Java API delete operation that requires a
   single call instead of two calls (delete and purge)
 - Refactor the High and Low Level intents, such that they don't use
   inheritance from a common base class.
 - Cleanup the return Intent objects representation in JSON. E.g.,
   the Dpid JSON should be just "dpid": <value> instead of
   "dpid": {
        "value": <value>
    }

Change-Id: Ia994a2026f57a1f176c5321c1952325e3b986097
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
new file mode 100644
index 0000000..ede564f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
@@ -0,0 +1,149 @@
+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.core.intent.ConstrainedShortestPathIntent;
+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.ShortestPathIntent;
+import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
+import net.onrc.onos.core.util.Dpid;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.restlet.resource.Delete;
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A class to access the high-level intents.
+ */
+public class IntentHighResource extends ServerResource {
+    private static final Logger log = LoggerFactory.getLogger(IntentHighResource.class);
+    // TODO need to assign proper application id.
+    private static final String APPLN_ID = "1";
+
+    /**
+     * Gets all high-level intents.
+     *
+     * @return a collection with all high-level intents.
+     */
+    @Get("json")
+    public Collection<Intent> retrieve() throws IOException {
+        IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
+                getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
+
+        IntentMap intentMap = pathRuntime.getHighLevelIntents();
+        Collection<Intent> intents = intentMap.getAllIntents();
+
+        return intents;
+    }
+
+    /**
+     * Adds a collection of high-level intents.
+     *
+     * @return the status of the operation (TBD).
+     */
+    @Post("json")
+    public String store(String jsonIntent) throws IOException {
+        IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext()
+                .getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
+        if (pathRuntime == null) {
+            log.warn("Failed to get path calc runtime");
+            return "";
+        }
+
+        String reply = "";
+        ObjectMapper mapper = new ObjectMapper();
+        ApplicationIntent[] addOperations = null;
+        try {
+            addOperations = mapper.readValue(jsonIntent, ApplicationIntent[].class);
+        } catch (JsonParseException ex) {
+            log.error("JsonParseException occurred", ex);
+        } catch (JsonMappingException ex) {
+            log.error("JsonMappingException occurred", ex);
+        } catch (IOException ex) {
+            log.error("IOException occurred", ex);
+        }
+        if (addOperations == null) {
+            return "";
+        }
+
+        //
+        // Process all intents one-by-one
+        //
+        // TODO: The Intent Type should be enum instead of a string,
+        // and we should use a switch statement below to process the
+        // different type of intents.
+        //
+        IntentOperationList intentOperations = new IntentOperationList();
+        for (ApplicationIntent oper : addOperations) {
+            String applnIntentId = APPLN_ID + ":" + oper.intentId();
+
+            IntentOperation.Operator operator = IntentOperation.Operator.ADD;
+            Dpid srcSwitchDpid = new Dpid(oper.srcSwitchDpid());
+            Dpid dstSwitchDpid = new Dpid(oper.dstSwitchDpid());
+
+            if (oper.intentType().equals("SHORTEST_PATH")) {
+                //
+                // Process Shortest-Path Intent
+                //
+                ShortestPathIntent spi =
+                    new ShortestPathIntent(applnIntentId,
+                                           srcSwitchDpid.value(),
+                                           oper.srcSwitchPort(),
+                                           MACAddress.valueOf(oper.matchSrcMac()).toLong(),
+                                           dstSwitchDpid.value(),
+                                           oper.dstSwitchPort(),
+                                           MACAddress.valueOf(oper.matchDstMac()).toLong());
+                spi.setPathFrozen(oper.isStaticPath());
+                intentOperations.add(operator, spi);
+            } else {
+                //
+                // Process Constrained Shortest-Path Intent
+                //
+                ConstrainedShortestPathIntent cspi =
+                    new ConstrainedShortestPathIntent(applnIntentId,
+                                                      srcSwitchDpid.value(),
+                                                      oper.srcSwitchPort(),
+                                                      MACAddress.valueOf(oper.matchSrcMac()).toLong(),
+                                                      dstSwitchDpid.value(),
+                                                      oper.dstSwitchPort(),
+                                                      MACAddress.valueOf(oper.matchDstMac()).toLong(),
+                                                      oper.bandwidth());
+                cspi.setPathFrozen(oper.isStaticPath());
+                intentOperations.add(operator, cspi);
+            }
+        }
+        // Apply the Intent Operations
+        pathRuntime.executeIntentOperations(intentOperations);
+
+        return reply;
+    }
+
+    /**
+     * Deletes all high-level intents.
+     *
+     * @return the status of the operation (TBD).
+     */
+    @Delete("json")
+    public String store() {
+        IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
+                getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
+
+        // Delete all intents
+        // TODO: The implementation below is broken - waiting for the Java API
+        // TODO: The deletion should use synchronous Java API?
+        pathRuntime.purgeIntents();
+        return "";      // TODO no reply yet from the purge intents call
+    }
+}