Return intent collection with details

Added backwards compatible flag to GET /intents/ to return full intent JSON.
Added GET /intents/application/{appId} to return application specifc intents.
Extended IntentService to include getIntentsByAppId(appId).
Removed hard-coded intent codec lookup in IntentWebResource.

Change-Id: I38e7b1dbd7669e654afe723f6ec3a4eb7a9af6fb
diff --git a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
index f4c1137..475bf6e 100644
--- a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
+++ b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.incubator.net.virtual.impl;
 
+import com.google.common.collect.ImmutableSet;
 import org.onlab.util.Tools;
 import org.onosproject.incubator.net.virtual.NetworkId;
 import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
@@ -33,6 +34,7 @@
 import org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualIntentProcessPhase;
 import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
 import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentSkipped;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
@@ -223,6 +225,18 @@
     }
 
     @Override
+    public Iterable<Intent> getIntentsByAppId(ApplicationId id) {
+        ImmutableSet.Builder<Intent> builder = ImmutableSet.builder();
+        for (Intent intent : intentStore.getIntents(networkId)) {
+            if (intent.appId().equals(id)) {
+                builder.add(intent);
+            }
+        }
+
+        return builder.build();
+    }
+
+    @Override
     public void addPending(IntentData intentData) {
         checkNotNull(intentData, INTENT_NULL);
         //TODO we might consider further checking / assertions
diff --git a/core/api/src/main/java/org/onosproject/net/intent/IntentService.java b/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
index 595e7e3..745d7f4 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
@@ -17,6 +17,7 @@
 
 
 import com.google.common.annotations.Beta;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.event.ListenerService;
 
 import java.util.List;
@@ -72,6 +73,14 @@
     Iterable<Intent> getIntents();
 
     /**
+     * Returns an iterable of all intents with this application ID.
+     *
+     * @param id the application ID to look up
+     * @return collection of intents
+     */
+    Iterable<Intent> getIntentsByAppId(ApplicationId id);
+
+    /**
      * Adds an intent data object to the pending map for processing.
      * <p>
      * This method is intended to only be called by core components, not
diff --git a/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java b/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
index e3e6277..870ad0b 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.intent;
 
 import com.google.common.collect.ImmutableMap;
+import org.onosproject.core.ApplicationId;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -26,6 +27,7 @@
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
 
 /**
  * Fake implementation of the intent service to assist in developing tests of
@@ -179,6 +181,15 @@
     }
 
     @Override
+    public Set<Intent> getIntentsByAppId(ApplicationId id) {
+        return Collections.unmodifiableSet(
+                intents.values().stream()
+                        .filter(intent -> intent.appId().equals(id))
+                        .collect(Collectors.toSet())
+        );
+    }
+
+    @Override
     public void addPending(IntentData intentData) {
         throw new UnsupportedOperationException();
     }
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java
index 8503447..17f489e 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java
@@ -16,6 +16,8 @@
 
 package org.onosproject.net.intent;
 
+import org.onosproject.core.ApplicationId;
+
 import java.util.List;
 
 /**
@@ -43,6 +45,11 @@
     }
 
     @Override
+    public Iterable<Intent> getIntentsByAppId(ApplicationId id) {
+        return null;
+    }
+
+    @Override
     public void addPending(IntentData intentData) {
 
     }
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index 642830e..bdfa106 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Sets;
 import org.onlab.graph.ScalarWeight;
 import org.onlab.graph.Weight;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.core.GroupId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultLink;
@@ -557,6 +558,12 @@
             this.number = number;
         }
 
+        public MockIntent(Long number, ApplicationId appId) {
+            super(appId, null, Collections.emptyList(),
+                    Intent.DEFAULT_INTENT_PRIORITY, null);
+            this.number = number;
+        }
+
         public MockIntent(Long number, Collection<NetworkResource> resources) {
             super(NetTestTools.APP_ID, null, resources, Intent.DEFAULT_INTENT_PRIORITY, null);
             this.number = number;
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 2b83fa8..da13b76 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -15,8 +15,10 @@
  */
 package org.onosproject.net.intent.impl;
 
+import com.google.common.collect.ImmutableSet;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.event.AbstractListenerManager;
@@ -87,8 +89,7 @@
 import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
 import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
 import static org.onosproject.security.AppGuard.checkPermission;
-import static org.onosproject.security.AppPermission.Type.INTENT_READ;
-import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
+import static org.onosproject.security.AppPermission.Type.*;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -291,6 +292,20 @@
     }
 
     @Override
+    public Iterable<Intent> getIntentsByAppId(ApplicationId id) {
+        checkPermission(INTENT_READ);
+
+        ImmutableSet.Builder<Intent> builder = ImmutableSet.builder();
+        for (Intent intent : store.getIntents()) {
+            if (intent.appId().equals(id)) {
+                builder.add(intent);
+            }
+        }
+
+        return builder.build();
+    }
+
+    @Override
     public void addPending(IntentData intentData) {
         checkPermission(INTENT_WRITE);
         checkNotNull(intentData, INTENT_NULL);
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index 14fb380..db92800 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -32,6 +32,7 @@
 import org.onosproject.common.event.impl.TestEventDispatcher;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.impl.TestCoreManager;
+import org.onosproject.net.NetTestTools;
 import org.onosproject.net.NetworkResource;
 import org.onosproject.net.flow.FlowRuleOperations;
 import org.onosproject.net.flow.FlowRuleOperationsContext;
@@ -557,8 +558,8 @@
         intents = Lists.newArrayList(service.getIntents());
         assertThat(intents, hasSize(0));
 
-        final MockIntent intent1 = new MockIntent(MockIntent.nextId());
-        final MockIntent intent2 = new MockIntent(MockIntent.nextId());
+        final MockIntent intent1 = new MockIntent(MockIntent.nextId(), NetTestTools.APP_ID);
+        final MockIntent intent2 = new MockIntent(MockIntent.nextId(), NetTestTools.APP_ID_2);
 
         listener.setLatch(2, Type.INSTALL_REQ);
         listener.setLatch(2, Type.INSTALLED);
@@ -575,6 +576,15 @@
         assertThat(intents, hasIntentWithId(intent1.id()));
         assertThat(intents, hasIntentWithId(intent2.id()));
         verifyState();
+
+        List<Intent> intentsAppId = Lists.newArrayList(service.getIntentsByAppId(NetTestTools.APP_ID));
+        assertThat(intentsAppId, hasSize(1));
+        assertThat(intentsAppId, hasIntentWithId(intent1.id()));
+
+        List<Intent> intentsAppId2 = Lists.newArrayList(service.getIntentsByAppId(NetTestTools.APP_ID_2));
+        assertThat(intentsAppId2, hasSize(1));
+        assertThat(intentsAppId2, hasIntentWithId(intent2.id()));
+        verifyState();
     }
 
     /**
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
index 297f70e..4a76749 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
@@ -17,14 +17,11 @@
 
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.JsonCodec;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.intent.SinglePointToMultiPointIntent;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.intent.PointToPointIntent;
-import org.onosproject.net.intent.HostToHostIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.IntentEvent;
@@ -43,6 +40,7 @@
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -53,6 +51,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -72,14 +71,7 @@
     private static final int WITHDRAW_EVENT_TIMEOUT_SECONDS = 5;
 
     private static final String APP_ID_NOT_FOUND = "Application Id not found";
-    private static final String HOST_TO_HOST_INTENT = "HostToHostIntent";
-    private static final String POINT_TO_POINT_INTENT = "PointToPointIntent";
-    private static final String SINGLE_TO_MULTI_POINT_INTENT =
-            "SinglePointToMultiPointIntent";
-    private static final String MULTI_TO_SINGLE_POINT_INTENT =
-            "MultiPointToSinglePointIntent";
-
-    private static final String INTENT = "Intent";
+    private static final String INTENTS = "intents";
     private static final String APP_ID = "appId";
     private static final String ID = "id";
     private static final String INTENT_PATHS = "paths";
@@ -90,17 +82,37 @@
     private UriInfo uriInfo;
 
     /**
+     * Returns the JSON codec for the specified intent.
+     *
+     * @param intent the intent instance
+     * @return JSON codec
+     */
+    public JsonCodec<Intent> codec(Intent intent) {
+        return Optional.ofNullable((JsonCodec<Intent>) codec(intent.getClass()))
+                .orElse(codec(Intent.class));
+    }
+
+    /**
      * Gets all intents.
      * Returns array containing all the intents in the system.
+     * @param detail flag to return full details of intents in list.
      *
      * @return 200 OK with array of all the intents in the system
      * @onos.rsModel Intents
      */
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getIntents() {
+    public Response getIntents(@QueryParam("detail") boolean detail) {
+        ObjectNode root = null;
         final Iterable<Intent> intents = get(IntentService.class).getIntents();
-        final ObjectNode root = encodeArray(Intent.class, "intents", intents);
+        if (detail) {
+            root = mapper().createObjectNode();
+            ArrayNode intentsNode = root.putArray(INTENTS);
+            intents.forEach(intent -> intentsNode.add(codec(intent).encode(intent, this)));
+        } else {
+            root = encodeArray(Intent.class, INTENTS, intents);
+        }
+
         return ok(root).build();
     }
 
@@ -179,18 +191,37 @@
         }
         nullIsNotFound(intent, INTENT_NOT_FOUND);
 
-        final ObjectNode root;
-        if (intent instanceof HostToHostIntent) {
-            root = codec(HostToHostIntent.class).encode((HostToHostIntent) intent, this);
-        } else if (intent instanceof PointToPointIntent) {
-            root = codec(PointToPointIntent.class).encode((PointToPointIntent) intent, this);
-        } else if (intent instanceof SinglePointToMultiPointIntent) {
-            root = codec(SinglePointToMultiPointIntent.class).encode((SinglePointToMultiPointIntent) intent, this);
-        } else if (intent instanceof MultiPointToSinglePointIntent) {
-            root = codec(MultiPointToSinglePointIntent.class).encode((MultiPointToSinglePointIntent) intent, this);
+        final ObjectNode root = codec(intent).encode(intent, this);
+
+        return ok(root).build();
+    }
+
+    /**
+     * Gets intents by application.
+     * Returns the intents specified by the application id.
+     * @param detail flag to return full details of intents in list.
+     *
+     * @param appId application identifier
+     * @return 200 OK with a collection of intents of given application id
+     * @onos.rsModel Intents
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("application/{appId}")
+    public Response getIntentsByAppId(@PathParam("appId") String appId, @QueryParam("detail") boolean detail) {
+        final ApplicationId app = get(CoreService.class).getAppId(appId);
+        nullIsNotFound(app, APP_ID_NOT_FOUND);
+
+        final Iterable<Intent> intents = get(IntentService.class).getIntentsByAppId(app);
+        ObjectNode root = null;
+        if (detail) {
+            root = mapper().createObjectNode();
+            ArrayNode intentsNode = root.putArray(INTENTS);
+            intents.forEach(intent -> intentsNode.add(codec(intent).encode(intent, this)));
         } else {
-            root = codec(Intent.class).encode(intent, this);
+            root = encodeArray(Intent.class, INTENTS, intents);
         }
+
         return ok(root).build();
     }
 
@@ -230,17 +261,7 @@
         List<Intent> installables =
                 intentService.getInstallableIntents(intent.key());
 
-        if (intent instanceof HostToHostIntent) {
-            root.put(INTENT_TYPE, HOST_TO_HOST_INTENT);
-        } else if (intent instanceof PointToPointIntent) {
-            root.put(INTENT_TYPE, POINT_TO_POINT_INTENT);
-        } else if (intent instanceof SinglePointToMultiPointIntent) {
-            root.put(INTENT_TYPE, SINGLE_TO_MULTI_POINT_INTENT);
-        } else if (intent instanceof MultiPointToSinglePointIntent) {
-            root.put(INTENT_TYPE, MULTI_TO_SINGLE_POINT_INTENT);
-        } else {
-            root.put(INTENT_TYPE, INTENT);
-        }
+        root.put(INTENT_TYPE, intent.getClass().getSimpleName());
 
         ArrayNode pathsNode = root.putArray(INTENT_PATHS);
 
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
index 318f90d..7867ab6 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
@@ -39,6 +39,8 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.HostId;
 import org.onosproject.net.Link;
 import org.onosproject.net.NetworkResource;
 import org.onosproject.net.PortNumber;
@@ -54,14 +56,17 @@
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.intent.ConnectivityIntent;
 import org.onosproject.net.intent.FakeIntentManager;
 import org.onosproject.net.intent.FlowRuleIntent;
+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.Key;
 import org.onosproject.net.intent.MockIdGenerator;
 import org.onosproject.net.intent.PathIntent;
+import org.onosproject.net.intent.PointToPointIntent;
 import org.onosproject.net.provider.ProviderId;
 
 
@@ -85,6 +90,7 @@
 import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
+import static org.onosproject.net.NetTestTools.hid;
 import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
 
 /**
@@ -116,6 +122,10 @@
     final HashSet<Intent> intents = new HashSet<>();
     final List<org.onosproject.net.intent.Intent> installableIntents = new ArrayList<>();
     private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
+    private static final ApplicationId APP_ID_2 = new DefaultApplicationId(2, "test2");
+
+    private final HostId hostId1 = hid("12:34:56:78:91:ab/1");
+    private final HostId hostId2 = hid("12:34:56:78:92:ab/1");
 
     final DeviceId deviceId1 = DeviceId.deviceId("1");
     final DeviceId deviceId2 = DeviceId.deviceId("2");
@@ -364,12 +374,18 @@
      */
     public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
         private final Intent intent;
+        private boolean detail = false;
         private String reason = "";
 
         public IntentJsonMatcher(Intent intentValue) {
             intent = intentValue;
         }
 
+        public IntentJsonMatcher(Intent intentValue, boolean detailValue) {
+            intent = intentValue;
+            detail = detailValue;
+        }
+
         @Override
         public boolean matchesSafely(JsonObject jsonIntent) {
             // check id
@@ -449,9 +465,139 @@
                 reason = "resources array empty";
                 return false;
             }
+
+            if (intent instanceof ConnectivityIntent && detail) {
+                return matchConnectivityIntent(jsonIntent);
+            }
+
             return true;
         }
 
+        public boolean matchesConnectPoint(ConnectPoint connectPoint, JsonObject jsonConnectPoint) {
+            // check device
+            final String jsonDevice = jsonConnectPoint.get("device").asString();
+            final String device = connectPoint.deviceId().toString();
+            if (!jsonDevice.equals(device)) {
+                reason = "device was " + jsonDevice;
+                return false;
+            }
+
+            // check port
+            final String jsonPort = jsonConnectPoint.get("port").asString();
+            final String port = connectPoint.port().toString();
+            if (!jsonPort.equals(port)) {
+                reason = "port was " + jsonPort;
+                return false;
+            }
+
+            return true;
+        }
+
+        private boolean matchHostToHostIntent(JsonObject jsonIntent) {
+            final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
+
+            // check host one
+            final String host1 = hostToHostIntent.one().toString();
+            final String jsonHost1 = jsonIntent.get("one").asString();
+            if (!host1.equals(jsonHost1)) {
+                reason = "host one was " + jsonHost1;
+                return false;
+            }
+
+            // check host 2
+            final String host2 = hostToHostIntent.two().toString();
+            final String jsonHost2 = jsonIntent.get("two").asString();
+            if (!host2.equals(jsonHost2)) {
+                reason = "host two was " + jsonHost2;
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Matches the JSON representation of a point to point intent.
+         *
+         * @param jsonIntent JSON representation of the intent
+         * @return true if the JSON matches the intent, false otherwise
+         */
+        private boolean matchPointToPointIntent(JsonObject jsonIntent) {
+            final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
+
+            // check ingress connection
+            final ConnectPoint ingress = pointToPointIntent.filteredIngressPoint().connectPoint();
+            final JsonObject jsonIngress = jsonIntent.get("ingressPoint").asObject();
+            final boolean ingressMatches = matchesConnectPoint(ingress, jsonIngress);
+
+            if (!ingressMatches) {
+                reason = "ingress was " + jsonIngress;
+                return false;
+            }
+
+            // check egress connection
+            final ConnectPoint egress = pointToPointIntent.filteredEgressPoint().connectPoint();
+            final JsonObject jsonEgress = jsonIntent.get("egressPoint").asObject();
+            final boolean egressMatches = matchesConnectPoint(egress, jsonEgress);
+
+            if (!egressMatches) {
+                reason = "egress was " + jsonEgress;
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * Matches the JSON representation of a connectivity intent. Calls the
+         * matcher for the connectivity intent subtype.
+         *
+         * @param jsonIntent JSON representation of the intent
+         * @return true if the JSON matches the intent, false otherwise
+         */
+        private boolean matchConnectivityIntent(JsonObject jsonIntent) {
+            final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent;
+
+            // check selector
+            final JsonObject jsonSelector = jsonIntent.get("selector").asObject();
+            final TrafficSelector selector = connectivityIntent.selector();
+            final Set<Criterion> criteria = selector.criteria();
+            final JsonArray jsonCriteria = jsonSelector.get("criteria").asArray();
+            if (jsonCriteria.size() != criteria.size()) {
+                reason = "size of criteria array is " + Integer.toString(jsonCriteria.size());
+                return false;
+            }
+
+            // check treatment
+            final JsonObject jsonTreatment = jsonIntent.get("treatment").asObject();
+            final TrafficTreatment treatment = connectivityIntent.treatment();
+            final List<Instruction> instructions = treatment.immediate();
+            final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray();
+            if (jsonInstructions.size() != instructions.size()) {
+                reason = "size of instructions array is " + Integer.toString(jsonInstructions.size());
+                return false;
+            }
+
+            // Check constraints
+            final JsonArray jsonConstraints = jsonIntent.get("constraints").asArray();
+            if (connectivityIntent.constraints() != null) {
+                if (connectivityIntent.constraints().size() != jsonConstraints.size()) {
+                    reason = "constraints array size was " + Integer.toString(jsonConstraints.size());
+                    return false;
+                }
+            } else if (jsonConstraints.size() != 0) {
+                reason = "constraint array not empty";
+                return false;
+            }
+
+            if (connectivityIntent instanceof HostToHostIntent) {
+                return matchHostToHostIntent(jsonIntent);
+            } else if (connectivityIntent instanceof PointToPointIntent) {
+                return matchPointToPointIntent(jsonIntent);
+            } else {
+                reason = "class of connectivity intent is unknown";
+                return false;
+            }
+        }
+
         @Override
         public void describeTo(Description description) {
             description.appendText(reason);
@@ -462,10 +608,11 @@
      * Factory to allocate an intent matcher.
      *
      * @param intent intent object we are looking for
+     * @param detail flag to verify if JSON contains detailed attributes for the intent's implementation class.
      * @return matcher
      */
-    private static IntentJsonMatcher matchesIntent(Intent intent) {
-        return new IntentJsonMatcher(intent);
+    private static IntentJsonMatcher matchesIntent(Intent intent, boolean detail) {
+        return new IntentJsonMatcher(intent, detail);
     }
 
     /**
@@ -668,10 +815,12 @@
      */
     public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
         private final Intent intent;
+        private boolean detail = false;
         private String reason = "";
 
-        public IntentJsonArrayMatcher(Intent intentValue) {
+        public IntentJsonArrayMatcher(Intent intentValue, boolean detailValue) {
             intent = intentValue;
+            detail = detailValue;
         }
 
         @Override
@@ -683,7 +832,7 @@
 
                 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
 
-                if (jsonIntent.names().size() != expectedAttributes) {
+                if (jsonIntent.names().size() != expectedAttributes && !detail) {
                     reason = "Found an intent with the wrong number of attributes";
                     return false;
                 }
@@ -693,7 +842,7 @@
                     intentFound = true;
 
                     //  We found the correct intent, check attribute values
-                    assertThat(jsonIntent, matchesIntent(intent));
+                    assertThat(jsonIntent, matchesIntent(intent, detail));
                 }
             }
             if (!intentFound) {
@@ -714,10 +863,11 @@
      * Factory to allocate an intent array matcher.
      *
      * @param intent intent object we are looking for
+     * @param detail flag to verify if JSON contains detailed attributes for the intent's implementation class.
      * @return matcher
      */
-    private static IntentJsonArrayMatcher hasIntent(Intent intent) {
-        return new IntentJsonArrayMatcher(intent);
+    private static IntentJsonArrayMatcher hasIntent(Intent intent, boolean detail) {
+        return new IntentJsonArrayMatcher(intent, detail);
     }
 
     /**
@@ -793,8 +943,8 @@
         final JsonArray jsonIntents = result.get("intents").asArray();
         assertThat(jsonIntents, notNullValue());
 
-        assertThat(jsonIntents, hasIntent(intent1));
-        assertThat(jsonIntents, hasIntent(intent2));
+        assertThat(jsonIntents, hasIntent(intent1, false));
+        assertThat(jsonIntents, hasIntent(intent2, false));
     }
 
     /**
@@ -832,13 +982,282 @@
         final String response = wt.path("intents/" + APP_ID.name()
                 + "/0").request().get(String.class);
         final JsonObject result = Json.parse(response).asObject();
-        assertThat(result, matchesIntent(intent));
+        assertThat(result, matchesIntent(intent, true));
 
         // Test get using numeric value
         final String responseNumeric = wt.path("intents/" + APP_ID.name()
                 + "/0x0").request().get(String.class);
         final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
-        assertThat(resultNumeric, matchesIntent(intent));
+        assertThat(resultNumeric, matchesIntent(intent, true));
+    }
+
+    /**
+     * Tests the result of the rest api GET when intents are defined and the detail flag is false.
+     */
+    @Test
+    public void testIntentsArrayWithoutDetail() {
+        replay(mockIntentService);
+
+        final PointToPointIntent intent1 =
+                PointToPointIntent.builder()
+                        .appId(APP_ID)
+                        .selector(selector1)
+                        .treatment(treatment1)
+                        .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+                        .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+                        .build();
+
+        final HashSet<NetworkResource> resources = new HashSet<>();
+        resources.add(new MockResource(1));
+        resources.add(new MockResource(2));
+        resources.add(new MockResource(3));
+
+        final HostToHostIntent intent2 =
+                HostToHostIntent.builder()
+                        .appId(APP_ID)
+                        .selector(selector2)
+                        .treatment(treatment2)
+                        .one(hostId1)
+                        .two(hostId2)
+                        .build();
+
+        intents.add(intent1);
+        intents.add(intent2);
+
+        final WebTarget wt = target();
+        final String response = wt.path("intents").queryParam("detail", false).request().get(String.class);
+        assertThat(response, containsString("{\"intents\":["));
+
+        final JsonObject result = Json.parse(response).asObject();
+        assertThat(result, notNullValue());
+
+        assertThat(result.names(), hasSize(1));
+        assertThat(result.names().get(0), is("intents"));
+
+        final JsonArray jsonIntents = result.get("intents").asArray();
+        assertThat(jsonIntents, notNullValue());
+
+        assertThat(jsonIntents, hasIntent(intent1, false));
+    }
+
+    /**
+     * Tests the result of the rest api GET when intents are defined and the detail flag is true.
+     */
+    @Test
+    public void testIntentsArrayWithDetail() {
+        replay(mockIntentService);
+
+        final PointToPointIntent intent1 =
+                PointToPointIntent.builder()
+                        .appId(APP_ID)
+                        .selector(selector1)
+                        .treatment(treatment1)
+                        .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+                        .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+                        .build();
+
+        final HashSet<NetworkResource> resources = new HashSet<>();
+        resources.add(new MockResource(1));
+        resources.add(new MockResource(2));
+        resources.add(new MockResource(3));
+
+        final HostToHostIntent intent2 =
+                HostToHostIntent.builder()
+                        .appId(APP_ID)
+                        .selector(selector2)
+                        .treatment(treatment2)
+                        .one(hostId1)
+                        .two(hostId2)
+                        .build();
+
+        intents.add(intent1);
+        intents.add(intent2);
+
+        final WebTarget wt = target();
+        final String response = wt.path("intents").queryParam("detail", true).request().get(String.class);
+        assertThat(response, containsString("{\"intents\":["));
+
+        final JsonObject result = Json.parse(response).asObject();
+        assertThat(result, notNullValue());
+
+        assertThat(result.names(), hasSize(1));
+        assertThat(result.names().get(0), is("intents"));
+
+        final JsonArray jsonIntents = result.get("intents").asArray();
+        assertThat(jsonIntents, notNullValue());
+
+        assertThat(jsonIntents, hasIntent(intent1, true));
+    }
+
+    /**
+     * Tests the result of the rest api GET when intents are defined.
+     */
+    @Test
+    public void testIntentsForApplicationWithoutDetail() {
+        final Intent intent1 =
+                PointToPointIntent.builder()
+                        .key(Key.of(0, APP_ID))
+                        .appId(APP_ID)
+                        .selector(selector1)
+                        .treatment(treatment1)
+                        .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+                        .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+                        .build();
+
+        final HostToHostIntent intent2 =
+                HostToHostIntent.builder()
+                        .key(Key.of(1, APP_ID_2))
+                        .appId(APP_ID_2)
+                        .selector(selector2)
+                        .treatment(treatment2)
+                        .one(hostId1)
+                        .two(hostId2)
+                        .build();
+
+        intents.add(intent1);
+        List<Intent> appIntents1 = new ArrayList<>();
+        appIntents1.add(intent1);
+
+        intents.add(intent2);
+        List<Intent> appIntents2 = new ArrayList<>();
+        appIntents2.add(intent2);
+
+        expect(mockIntentService.getIntentsByAppId(APP_ID))
+                .andReturn(appIntents1)
+                .anyTimes();
+        expect(mockIntentService.getIntentsByAppId(APP_ID_2))
+                .andReturn(appIntents2)
+                .anyTimes();
+        replay(mockIntentService);
+
+        expect(mockCoreService.getAppId(APP_ID.name()))
+                .andReturn(APP_ID).anyTimes();
+        expect(mockCoreService.getAppId(APP_ID_2.name()))
+                .andReturn(APP_ID_2).anyTimes();
+        replay(mockCoreService);
+
+
+        final WebTarget wt = target();
+        // Verify intents for app_id
+        final String response1 = wt.path("intents/application/" + APP_ID.name()).request().get(String.class);
+        assertThat(response1, containsString("{\"intents\":["));
+
+        final JsonObject result1 = Json.parse(response1).asObject();
+        assertThat(result1, notNullValue());
+
+        assertThat(result1.names(), hasSize(1));
+        assertThat(result1.names().get(0), is("intents"));
+
+        final JsonArray jsonIntents1 = result1.get("intents").asArray();
+        assertThat(jsonIntents1, notNullValue());
+        assertThat(jsonIntents1.size(), is(1));
+
+        assertThat(jsonIntents1, hasIntent(intent1, false));
+        assertThat(jsonIntents1, is(not(hasIntent(intent2, false))));
+
+        // Verify intents for app_id_2 with detail = false
+        final String response2 = wt.path("intents/application/" + APP_ID_2.name())
+                .queryParam("detail", false).request().get(String.class);
+        assertThat(response2, containsString("{\"intents\":["));
+
+        final JsonObject result2 = Json.parse(response2).asObject();
+        assertThat(result2, notNullValue());
+
+        assertThat(result2.names(), hasSize(1));
+        assertThat(result2.names().get(0), is("intents"));
+
+        final JsonArray jsonIntents2 = result2.get("intents").asArray();
+        assertThat(jsonIntents2, notNullValue());
+        assertThat(jsonIntents2.size(), is(1));
+
+        assertThat(jsonIntents2, hasIntent(intent2, false));
+        assertThat(jsonIntents2, is(not(hasIntent(intent1, false))));
+    }
+
+    /**
+     * Tests the result of the rest api GET when intents are defined and the detail flag is true.
+     */
+    @Test
+    public void testIntentsForApplicationWithDetail() {
+        final Intent intent1 =
+                PointToPointIntent.builder()
+                        .key(Key.of(0, APP_ID))
+                        .appId(APP_ID)
+                        .selector(selector1)
+                        .treatment(treatment1)
+                        .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+                        .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+                        .build();
+
+        final HostToHostIntent intent2 =
+                HostToHostIntent.builder()
+                        .key(Key.of(1, APP_ID_2))
+                        .appId(APP_ID_2)
+                        .selector(selector2)
+                        .treatment(treatment2)
+                        .one(hostId1)
+                        .two(hostId2)
+                        .build();
+
+        intents.add(intent1);
+        List<Intent> appIntents1 = new ArrayList<>();
+        appIntents1.add(intent1);
+
+        intents.add(intent2);
+        List<Intent> appIntents2 = new ArrayList<>();
+        appIntents2.add(intent2);
+
+        expect(mockIntentService.getIntentsByAppId(APP_ID))
+                .andReturn(appIntents1)
+                .anyTimes();
+        expect(mockIntentService.getIntentsByAppId(APP_ID_2))
+                .andReturn(appIntents2)
+                .anyTimes();
+        replay(mockIntentService);
+
+        expect(mockCoreService.getAppId(APP_ID.name()))
+                .andReturn(APP_ID).anyTimes();
+        expect(mockCoreService.getAppId(APP_ID_2.name()))
+                .andReturn(APP_ID_2).anyTimes();
+        replay(mockCoreService);
+
+
+        final WebTarget wt = target();
+        // Verify intents for app_id
+        final String response1 = wt.path("intents/application/" + APP_ID.name())
+                .queryParam("detail", true).request().get(String.class);
+        assertThat(response1, containsString("{\"intents\":["));
+
+        final JsonObject result1 = Json.parse(response1).asObject();
+        assertThat(result1, notNullValue());
+
+        assertThat(result1.names(), hasSize(1));
+        assertThat(result1.names().get(0), is("intents"));
+
+        final JsonArray jsonIntents1 = result1.get("intents").asArray();
+        assertThat(jsonIntents1, notNullValue());
+        assertThat(jsonIntents1.size(), is(1));
+
+        assertThat(jsonIntents1, hasIntent(intent1, true));
+        assertThat(jsonIntents1, is(not(hasIntent(intent2, true))));
+
+        // Verify intents for app_id_2
+        final String response2 = wt.path("intents/application/" + APP_ID_2.name())
+                .queryParam("detail", true).request().get(String.class);
+        assertThat(response2, containsString("{\"intents\":["));
+
+        final JsonObject result2 = Json.parse(response2).asObject();
+        assertThat(result2, notNullValue());
+
+        assertThat(result2.names(), hasSize(1));
+        assertThat(result2.names().get(0), is("intents"));
+
+        final JsonArray jsonIntents2 = result2.get("intents").asArray();
+        assertThat(jsonIntents2, notNullValue());
+        assertThat(jsonIntents2.size(), is(1));
+
+        assertThat(jsonIntents2, hasIntent(intent2, true));
+        assertThat(jsonIntents2, is(not(hasIntent(intent1, true))));
     }
 
     /**
@@ -975,13 +1394,13 @@
         final String response = wt.path("intents/installables/" + APP_ID.name()
                 + "/" + intentId).request().get(String.class);
         final JsonObject result = Json.parse(response).asObject();
-        assertThat(result.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent));
+        assertThat(result.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent, false));
 
         // Test get using numeric value
         final String responseNumeric = wt.path("intents/installables/" + APP_ID.name()
                 + "/" + Long.toHexString(intentId)).request().get(String.class);
         final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
-        assertThat(resultNumeric.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent));
+        assertThat(resultNumeric.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent, false));
     }
 
     /**