Implementation of REST POST API for creating intents
- codec for constraint decode
- codec for intent decode
- POST method for intents
- unit tests for codecs and POST method

Change-Id: Ibc0ef8f99a0c0664710a733985424c77010c49b5
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java
index a45ae87..36ff8fa 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java
@@ -17,31 +17,46 @@
 
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
+import org.onosproject.core.CoreService;
 import org.onosproject.net.NetworkResource;
+import org.onosproject.net.intent.HostToHostIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.PointToPointIntent;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
 
 /**
  * Intent JSON codec.
  */
 public final class IntentCodec extends JsonCodec<Intent> {
 
+    protected static final String TYPE = "type";
+    protected static final String ID = "id";
+    protected static final String APP_ID = "appId";
+    protected static final String DETAILS = "details";
+    protected static final String STATE = "state";
+    protected static final String PRIORITY = "priority";
+    protected static final String RESOURCES = "resources";
+    protected static final String MISSING_MEMBER_MESSAGE =
+            " member is required in Intent";
+
     @Override
     public ObjectNode encode(Intent intent, CodecContext context) {
         checkNotNull(intent, "Intent cannot be null");
         final ObjectNode result = context.mapper().createObjectNode()
-                .put("type", intent.getClass().getSimpleName())
-                .put("id", intent.id().toString())
-                .put("appId", intent.appId().toString())
-                .put("details", intent.toString());
+                .put(TYPE, intent.getClass().getSimpleName())
+                .put(ID, intent.id().toString())
+                .put(APP_ID, intent.appId().toString())
+                .put(DETAILS, intent.toString());
 
-        final ArrayNode jsonResources = result.putArray("resources");
+        final ArrayNode jsonResources = result.putArray(RESOURCES);
 
         for (final NetworkResource resource : intent.resources()) {
             jsonResources.add(resource.toString());
@@ -50,9 +65,47 @@
         IntentService service = context.getService(IntentService.class);
         IntentState state = service.getIntentState(intent.key());
         if (state != null) {
-            result.put("state", state.toString());
+            result.put(STATE, state.toString());
         }
 
         return result;
     }
+
+    @Override
+    public Intent decode(ObjectNode json, CodecContext context) {
+        checkNotNull(json, "JSON cannot be null");
+
+        String type = nullIsIllegal(json.get(TYPE),
+                TYPE + MISSING_MEMBER_MESSAGE).asText();
+
+        if (type.equals(PointToPointIntent.class.getSimpleName())) {
+            return context.codec(PointToPointIntent.class).decode(json, context);
+        } else if (type.equals(HostToHostIntent.class.getSimpleName())) {
+            return context.codec(HostToHostIntent.class).decode(json, context);
+        }
+
+        throw new IllegalArgumentException("Intent type "
+                + type + " is not supported");
+    }
+
+    /**
+     * Extracts base intent specific attributes from a JSON object
+     * and adds them to a builder.
+     *
+     * @param json root JSON object
+     * @param context code context
+     * @param builder builder to use for storing the attributes
+     */
+    public static void intentAttributes(ObjectNode json, CodecContext context,
+                                    Intent.Builder builder) {
+        short appId = (short) nullIsIllegal(json.get(IntentCodec.APP_ID),
+                IntentCodec.TYPE + IntentCodec.MISSING_MEMBER_MESSAGE).asInt();
+        CoreService service = context.getService(CoreService.class);
+        builder.appId(service.getAppId(appId));
+
+        JsonNode priorityJson = json.get(IntentCodec.PRIORITY);
+        if (priorityJson != null) {
+            builder.priority(priorityJson.asInt());
+        }
+    }
 }