ONOS-5504: Added REST API for administering OFAgent.

Change-Id: Idc9a18fc82ec23fbb8348fe213f8007e362253ac
diff --git a/apps/ofagent/BUCK b/apps/ofagent/BUCK
index 1c8ee1e..fedf257 100644
--- a/apps/ofagent/BUCK
+++ b/apps/ofagent/BUCK
@@ -10,12 +10,16 @@
     '//lib:netty-codec',
     '//lib:netty-handler',
     '//lib:openflowj-3.0',
+    '//lib:javax.ws.rs-api',
+    '//utils/rest:onlab-rest',
 ]
 
 TEST_DEPS = [
     '//lib:TEST_ADAPTERS',
     '//core/api:onos-api-tests',
     '//core/common:onos-core-common-tests',
+    '//lib:TEST_REST',
+    '//lib:jersey-server',
 ]
 
 EXCLUDED_BUNDLES = [
@@ -25,6 +29,7 @@
 osgi_jar_with_tests (
     deps = COMPILE_DEPS,
     test_deps = TEST_DEPS,
+    web_context = '/onos/v1/ofagent',
 )
 
 onos_app (
diff --git a/apps/ofagent/pom.xml b/apps/ofagent/pom.xml
index 3c45384..8b66199 100644
--- a/apps/ofagent/pom.xml
+++ b/apps/ofagent/pom.xml
@@ -73,6 +73,8 @@
             <groupId>org.onosproject</groupId>
             <artifactId>onlab-osgi</artifactId>
             <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.onosproject</groupId>
@@ -126,6 +128,49 @@
             <artifactId>netty-all</artifactId>
             <version>${netty4.version}</version>
         </dependency>
+
+        <!-- REST api dependencies -->
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-jetty</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
     <build>
@@ -136,9 +181,18 @@
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Include-Resource>
+                            WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
+                            {maven-resources}
+                        </Include-Resource>
                         <Embed-Dependency>
                             openflowj
                         </Embed-Dependency>
+                        <Import-Package>
+                            *,org.glassfish.jersey.servlet
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
                     </instructions>
                 </configuration>
             </plugin>
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentCodec.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentCodec.java
new file mode 100644
index 0000000..6e6e772
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentCodec.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.rest;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Sets;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFController;
+import org.onosproject.ofagent.impl.DefaultOFAgent;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * OpenFlow agent JSON codec.
+ */
+public final class OFAgentCodec extends JsonCodec<OFAgent> {
+
+    @Override
+    public ObjectNode encode(OFAgent ofAgent, CodecContext context) {
+        checkNotNull(ofAgent, "OFAgent cannot be null");
+
+        ObjectMapper mapper = context.mapper();
+        ObjectNode ofAgentNode = mapper.createObjectNode();
+        ofAgentNode
+                .put("networkId", ofAgent.networkId().toString())
+                .put("state", ofAgent.state().toString());
+
+        ArrayNode controllers = mapper.createArrayNode();
+        ofAgent.controllers().forEach(ofController -> controllers.add((new OFControllerCodec()).encode(ofController,
+                                                                                                       context)));
+        ofAgentNode.set("controllers", controllers);
+
+        return ofAgentNode;
+    }
+
+    public OFAgent decode(ObjectNode json, CodecContext context) {
+        JsonNode networkId = json.get("networkId");
+        checkNotNull(networkId);
+
+        checkNotNull(json.get("controllers"));
+        checkState(json.get("controllers").isArray());
+        Set<OFController> controllers = Sets.newHashSet();
+        json.get("controllers").forEach(jsonController -> controllers.add((new
+                OFControllerCodec()).decode((ObjectNode) jsonController, context)));
+
+        return DefaultOFAgent.builder()
+                .networkId(NetworkId.networkId(networkId.asLong()))
+                .controllers(controllers)
+                .state(OFAgent.State.STOPPED)
+                .build();
+    }
+
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebApplication.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebApplication.java
new file mode 100644
index 0000000..173e1cd
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.ofagent.rest;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+
+/**
+ * OFAgent Web application.
+ */
+public class OFAgentWebApplication extends AbstractWebApplication {
+    @Override
+    public Set<Class<?>> getClasses() {
+        return getClasses(OFAgentWebResource.class);
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebResource.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebResource.java
new file mode 100644
index 0000000..58d22a1
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebResource.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.rest;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+import org.onosproject.ofagent.api.OFAgentService;
+import org.onosproject.rest.AbstractWebResource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static javax.ws.rs.core.Response.Status.*;
+
+
+/**
+ * Manage virtual switch and controller mapping.
+ */
+@Path("service")
+public class OFAgentWebResource extends AbstractWebResource {
+
+    private static final String OFAGENT_NOT_FOUND = "OFAgent not found";
+    private static final String OFAGENTS_NOT_FOUND = "OFAgent set not found";
+    private static final String OFAGENT_CREATED = "OFAgent created";
+    private static final String OFAGENT_NOT_CREATED = "OFAgent not created";
+    private static final String OFAGENT_STARTED = "OFAgent started";
+    private static final String OFAGENT_NOT_STARTED = "OFAgent not started";
+    private static final String OFAGENT_UPDATED = "OFAgent updated";
+    private static final String OFAGENT_NOT_UPDATED = "OFAgent not updated";
+
+     /**
+     * Lists OpenFlow agents.
+     * Shows OpenFlow agents for all virtual networks.
+     *
+     * @return 200 OK if set exists, 500 INTERNAL SERVER ERROR otherwise
+     */
+    @GET
+    @Path("ofagents")
+    public Response listOFAgents() {
+        OFAgentService service = get(OFAgentService.class);
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode root = mapper.createObjectNode();
+        ArrayNode ofAgentsArray = mapper.createArrayNode();
+        if (service.agents() == null) {
+            return Response.status(INTERNAL_SERVER_ERROR)
+                    .entity(OFAGENTS_NOT_FOUND).build();
+        } else {
+            service.agents().forEach(ofAgent -> ofAgentsArray.add((new OFAgentCodec()).encode(ofAgent, this)));
+
+            root.set("ofAgents", ofAgentsArray);
+            return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
+        }
+
+    }
+
+    /**
+     * Lists OpenFlow agent.
+     * Shows OpenFlow agent for given network.
+     *
+     * @param networkId OFAgent networkId
+     * @return 200 OK if OFAgent exists, 404 NOT FOUND otherwise
+     */
+    @GET
+    @Path("ofagent/{networkId}")
+    public Response listOFAgent(@PathParam("networkId") long networkId) {
+        OFAgentService service = get(OFAgentService.class);
+        OFAgent ofAgent = service.agent(NetworkId.networkId(networkId));
+        if (ofAgent == null) {
+            return Response.status(NOT_FOUND)
+                    .entity(OFAGENT_NOT_FOUND).build();
+        } else {
+            return Response.ok((new OFAgentCodec()).encode(ofAgent, this), MediaType
+                    .APPLICATION_JSON_TYPE)
+                    .build();
+        }
+    }
+
+    /**
+     * Adds a new OpenFlow agent.
+     * Creates a new OpenFlow agent and adds it to OpenFlow agent store.
+     *
+     * @param stream JSON stream
+     * @return 201 CREATED , 400 BAD REQUEST if stream cannot be decoded to OFAgent
+     * @throws IOException if request cannot be parsed
+     */
+    @POST
+    @Path("ofagent-create")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createOFAgent(InputStream stream) throws IOException {
+        OFAgentAdminService adminService = get(OFAgentAdminService.class);
+
+        OFAgent ofAgent = (new OFAgentCodec()).decode((ObjectNode) mapper().readTree(stream), this);
+        if (ofAgent == null) {
+            return Response.status(BAD_REQUEST)
+                    .entity(OFAGENT_NOT_CREATED).build();
+        } else {
+            adminService.createAgent(ofAgent);
+            return Response.status(CREATED).entity(OFAGENT_CREATED).build();
+        }
+    }
+
+    /**
+     * Starts OpenFlow agent.
+     * Starts OpenFlow agent for the given network.
+     *
+     * @param stream JSON stream
+     * @return 200 OK if OFAgent was started, 404 NOT FOUND when OF agent does not exist, 400 BAD REQUEST otherwise
+     * @throws IOException if request cannot be parsed
+     */
+    @POST
+    @Path("ofagent-start")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response startOFAgent(InputStream stream) throws IOException {
+        OFAgentAdminService adminService = get(OFAgentAdminService.class);
+
+        ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+        JsonNode networkId = jsonTree.get("networkId");
+
+        if (networkId == null) {
+            return Response.status(BAD_REQUEST)
+                    .entity(OFAGENT_NOT_STARTED).build();
+        } else if (get(OFAgentService.class).agent(NetworkId.networkId(networkId.asLong())) == null) {
+            return Response.status(NOT_FOUND)
+                    .entity(OFAGENT_NOT_STARTED).build();
+        } else {
+            adminService.startAgent(NetworkId.networkId(networkId.asLong()));
+            return Response.status(OK).entity(OFAGENT_STARTED).build();
+        }
+    }
+
+    /**
+     * Updates OpenFlow agent.
+     * Updates existing OpenFlow agent for the given network.
+     *
+     * @param stream JSON stream
+     * @return 200 OK if OFAgent was updated, 404 NOT FOUND when OF agent does not exist, 400 BAD REQUEST otherwise
+     * @throws IOException if request cannot be parsed
+     */
+    @PUT
+    @Path("ofagent-update")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateOFAgent(InputStream stream) throws IOException {
+        OFAgentAdminService adminService = get(OFAgentAdminService.class);
+
+        OFAgent ofAgent = (new OFAgentCodec()).decode((ObjectNode) mapper().readTree(stream), this);
+
+        if (ofAgent == null) {
+            return Response.status(NOT_FOUND)
+                    .entity(OFAGENT_NOT_UPDATED).build();
+        } else if (get(OFAgentService.class).agent(ofAgent.networkId()) == null) {
+            return Response.status(NOT_FOUND)
+                    .entity(OFAGENT_NOT_UPDATED).build();
+        }
+
+        adminService.updateAgent(ofAgent);
+        return Response.status(OK).entity(OFAGENT_UPDATED).build();
+    }
+
+
+    /**
+     * Stops OFAgent.
+     * Stops OFAgent for the given virtual network.
+     *
+     * @param stream JSON stream
+     * @return 204 NO CONTENT if OpenFlow agent was stopped, 404 NOT FOUND otherwise
+     * @throws IOException if request cannot be parsed
+     */
+    @POST
+    @Path("ofagent-stop")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response stopOFAgent(InputStream stream) throws IOException {
+
+        OFAgentAdminService adminService = get(OFAgentAdminService.class);
+        ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+        JsonNode networkId = jsonTree.get("networkId");
+
+        if (get(OFAgentService.class).agent(NetworkId.networkId(networkId.asLong())) == null) {
+            return Response.status(NOT_FOUND)
+                    .entity(OFAGENT_NOT_FOUND).build();
+        }
+
+        adminService.stopAgent(NetworkId.networkId(networkId.asLong()));
+        return Response.noContent().build();
+    }
+
+
+    /**
+     * Deletes OFAgent.
+     * Removes OFAgent for the given virtual network from repository.
+     *
+     * @param networkId OFAgent networkId
+     * @return 200 OK if OFAgent was removed, 404 NOT FOUND when OF agent does not exist, 400 BAD REQUEST otherwise
+     */
+    @DELETE
+    @Path("ofagent-remove/{networkId}")
+    public Response removeOFAgent(@PathParam("networkId") long networkId) {
+        if (get(OFAgentService.class).agent(NetworkId.networkId(networkId)) == null) {
+            return Response.status(BAD_REQUEST)
+                    .entity(OFAGENT_NOT_FOUND).build();
+        }
+
+        OFAgentAdminService adminService = get(OFAgentAdminService.class);
+        OFAgent removed = adminService.removeAgent(NetworkId.networkId(networkId));
+        if (removed != null) {
+            return Response.ok((new OFAgentCodec()).encode(removed, this), MediaType
+                    .APPLICATION_JSON_TYPE)
+                    .build();
+        } else {
+            return Response.status(NOT_FOUND)
+                    .entity(OFAGENT_NOT_FOUND).build();
+        }
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFControllerCodec.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFControllerCodec.java
new file mode 100644
index 0000000..e50dccc
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFControllerCodec.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.rest;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.ofagent.api.OFController;
+import org.onosproject.ofagent.impl.DefaultOFController;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * OFController JSON codec.
+ */
+public final class OFControllerCodec extends JsonCodec<OFController> {
+
+    private static final String IP = "ip";
+    private static final String PORT = "port";
+
+    private static final String MISSING_MEMBER_MESSAGE = " member is required in OFController";
+
+    @Override
+    public ObjectNode encode(OFController ofController, CodecContext context) {
+        checkNotNull(ofController, "OFController cannot be null");
+
+        return context.mapper().createObjectNode()
+                .put(IP, String.valueOf(ofController.ip()))
+                .put(PORT, String.valueOf(ofController.port()));
+
+    }
+
+    @Override
+    public OFController decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        // parse ip address
+        int id = nullIsIllegal(json.get(IP), IP + MISSING_MEMBER_MESSAGE).asInt();
+
+        // parse port
+        String name = nullIsIllegal(json.get(PORT), PORT + MISSING_MEMBER_MESSAGE).asText();
+
+        return DefaultOFController.of(IpAddress.valueOf(id),
+                                      TpPort.tpPort(Integer.valueOf(name)));
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/package-info.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/package-info.java
new file mode 100644
index 0000000..36977f9
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * REST API for OFAgent.
+ */
+package org.onosproject.ofagent.rest;
\ No newline at end of file
diff --git a/apps/ofagent/src/main/webapp/WEB-INF/web.xml b/apps/ofagent/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..5c82b0d
--- /dev/null
+++ b/apps/ofagent/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>OFAgent REST API v1.0</display-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.onosproject.ofagent.rest.OFAgentWebApplication</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/apps/ofagent/src/test/java/org/onosproject/ofagent/rest/OFAgentWebResourceTest.java b/apps/ofagent/src/test/java/org/onosproject/ofagent/rest/OFAgentWebResourceTest.java
new file mode 100644
index 0000000..026a9bc
--- /dev/null
+++ b/apps/ofagent/src/test/java/org/onosproject/ofagent/rest/OFAgentWebResourceTest.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.ofagent.rest;
+
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonObject;
+import com.google.common.collect.Sets;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onlab.rest.BaseResource;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+import org.onosproject.ofagent.api.OFAgentService;
+import org.onosproject.ofagent.api.OFController;
+import org.onosproject.ofagent.impl.DefaultOFAgent;
+import org.onosproject.ofagent.impl.DefaultOFController;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.Set;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.onosproject.ofagent.api.OFAgent.State.STOPPED;
+
+
+/**
+ * Test class for OFAgent application REST resource.
+ */
+public class OFAgentWebResourceTest extends JerseyTest {
+
+
+    private static final Set<OFController> CONTROLLER_SET_1 = Sets.newHashSet(
+            DefaultOFController.of(
+                    IpAddress.valueOf("147.91.1.4"),
+                    TpPort.tpPort(6633)));
+
+    private static final Set<OFController> CONTROLLER_SET_2 = Sets.newHashSet(
+            DefaultOFController.of(
+                    IpAddress.valueOf("147.91.4.25"),
+                    TpPort.tpPort(6633)),
+            DefaultOFController.of(
+                    IpAddress.valueOf("147.91.4.27"),
+                    TpPort.tpPort(6653)));
+
+    private static final Set<OFController> CONTROLLER_SET = Sets.newHashSet(
+            DefaultOFController.of(
+                    IpAddress.valueOf("147.91.2.11"),
+                    TpPort.tpPort(6633)),
+            DefaultOFController.of(
+                    IpAddress.valueOf("147.91.2.9"),
+                    TpPort.tpPort(6633)),
+            DefaultOFController.of(
+                    IpAddress.valueOf("147.91.2.17"),
+                    TpPort.tpPort(6653)));
+
+    private static final NetworkId NETWORK_1 = NetworkId.networkId(1);
+    private static final NetworkId NETWORK_2 = NetworkId.networkId(2);
+    private static final NetworkId NETWORK = NetworkId.networkId(3);
+
+    private static final OFAgent OF_AGENT = DefaultOFAgent.builder()
+            .networkId(NETWORK)
+            .controllers(CONTROLLER_SET)
+            .state(STOPPED)
+            .build();
+
+    private Set<OFAgent> agents = Sets.newHashSet(DefaultOFAgent.builder()
+                                                  .networkId(NETWORK_1)
+                                                  .controllers(CONTROLLER_SET_1)
+                                                  .state(STOPPED)
+                                                  .build(),
+                                          DefaultOFAgent.builder()
+                                                  .networkId(NETWORK_2)
+                                                  .controllers(CONTROLLER_SET_2)
+                                                  .state(STOPPED)
+                                                  .build(),
+                                          OF_AGENT);
+
+    private Set<OFAgent> empty = Sets.newHashSet();
+
+    private final OFAgentAdminService mockOFAgentAdminService = createMock(OFAgentAdminService.class);
+    private final OFAgentService mockOFAgentService = createMock(OFAgentService.class);
+
+    /**
+     * Constructs OFAgent Web application test instance.
+     */
+    public OFAgentWebResourceTest() {
+        super(ResourceConfig.forApplicationClass(OFAgentWebApplication.class));
+    }
+
+    /**
+     * Sets up the global values for all the tests.
+     */
+    @Before
+    public void setUpMocks() {
+        ServiceDirectory testDirectory = new TestServiceDirectory()
+                .add(OFAgentAdminService.class, mockOFAgentAdminService)
+                .add(OFAgentService.class, mockOFAgentService);
+        BaseResource.setServiceDirectory(testDirectory);
+    }
+
+    /**
+     * Cleans up.
+     */
+    @After
+    public void tearDownMocks() {
+    }
+
+    /**
+     * Tests the result of the rest api GET when there are OFAgents.
+     *
+     * @throws IOException
+     */
+    @Test
+    public void testNonEmptyOFAgentSet() throws IOException {
+        expect(mockOFAgentService.agents()).andReturn(agents).anyTimes();
+        replay(mockOFAgentService);
+
+        final WebTarget wt = target();
+        assertNotNull("WebTarget is null", wt);
+        assertNotNull("WebTarget request is null", wt.request());
+        final String response = wt.path("service/ofagents").request().get(String.class);
+        final JsonObject result = Json.parse(response).asObject();
+        assertThat(result, notNullValue());
+        assertThat(result.names(), hasSize(1));
+        assertThat(result.names().get(0), is("ofAgents"));
+
+        mockOFAgentService.agents().forEach(ofAgent -> {
+
+            String expectedJsonStringNetworkId = "\"networkId\":\"" + ofAgent.networkId().id() + "\"";
+            assertThat(response, containsString(expectedJsonStringNetworkId));
+
+            String expectedJsonStringState = "\"state\":\"" + ofAgent.state() + "\"";
+            assertThat(response, containsString(expectedJsonStringState));
+
+            ofAgent.controllers().forEach(ofController -> {
+                String expectedJsonStringIP = "\"ip\":\"" + ofController.ip() + "\"";
+                assertThat(response, containsString(expectedJsonStringIP));
+
+                String expectedJsonStringPort = "\"port\":\"" + ofController.port() + "\"";
+                assertThat(response, containsString(expectedJsonStringPort));
+            });
+        });
+
+        verify(mockOFAgentService);
+    }
+
+    /**
+     * Tests the result of the rest api GET when there are no OFAgents.
+     *
+     * @throws IOException
+     */
+    @Test
+    public void testEmptyOFAgentSet() throws IOException {
+        expect(mockOFAgentService.agents()).andReturn(empty).anyTimes();
+        replay(mockOFAgentService);
+
+        final WebTarget wt = target();
+        assertNotNull("WebTarget is null", wt);
+        assertNotNull("WebTarget request is null", wt.request());
+        final String response = wt.path("service/ofagents").request().get(String.class);
+        final JsonObject result = Json.parse(response).asObject();
+        assertThat(result, notNullValue());
+        assertThat(result.names(), hasSize(1));
+        assertThat(response, is("{\"ofAgents\":[]}"));
+
+        verify(mockOFAgentService);
+    }
+
+    /**
+     * Tests the result of the rest api GET for OFAgent.
+     *
+     * @throws IOException
+     */
+    @Test
+    public void testOFAgent() throws IOException {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes();
+        replay(mockOFAgentService);
+
+        final WebTarget wt = target();
+        assertNotNull("WebTarget is null", wt);
+        assertNotNull("WebTarget request is null", wt.request());
+        final Response response = wt.path("service/ofagent/" + NETWORK).request().get();
+        final JsonObject result = Json.parse(response.readEntity(String.class)).asObject();
+        assertThat(result, notNullValue());
+        assertThat(result.names(), hasSize(3));
+        assertThat(result.get("networkId").asString(), is(NETWORK.id().toString()));
+        assertThat(result.get("state").asString(), is(STOPPED.toString()));
+
+        verify(mockOFAgentService);
+    }
+
+
+    /**
+     * Tests the result of the rest api GET for non-existent OFAgent.
+     *
+     * @throws IOException
+     */
+    @Test
+    public void testNonExistentOFAgent() throws IOException {
+        expect(mockOFAgentService.agent(anyObject())).andReturn(null).anyTimes();
+        replay(mockOFAgentService);
+
+        final WebTarget wt = target();
+        assertNotNull("WebTarget is null", wt);
+        assertNotNull("WebTarget request is null", wt.request());
+        final Response response = wt.path("service/ofagent/" + NETWORK_1).request().get();
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND));
+
+        verify(mockOFAgentService);
+    }
+
+
+    /**
+     * Tests creating an OFAgent with POST.
+     */
+    @Test
+    public void testOFAgentCreate() {
+        mockOFAgentAdminService.createAgent(anyObject());
+        expectLastCall().anyTimes();
+        replay(mockOFAgentAdminService);
+
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-ofagent-create.json");
+        assertNotNull("post-ofagent-create.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-create")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
+
+        verify(mockOFAgentAdminService);
+    }
+
+    /**
+     * Tests creating an OFAgent with bad POST request.
+     */
+    @Test
+    public void testOFAgentCreateBadRequest() {
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-bad-request.json");
+        assertNotNull("post-bad-request.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-create")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_INTERNAL_ERROR));
+    }
+
+    /**
+     * Tests updating an OFAgent with PUT.
+     */
+    @Test
+    public void testOFAgentUpdate() {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes();
+        replay(mockOFAgentService);
+
+        mockOFAgentAdminService.updateAgent(anyObject());
+        expectLastCall().anyTimes();
+        replay(mockOFAgentAdminService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("put-ofagent-update.json");
+        assertNotNull("put-ofagent-update.json is null", jsonStream);
+        WebTarget wt = target();
+        Response response = wt.path("service/ofagent-update")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .put(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
+        assertThat(response.readEntity(String.class), containsString("OFAgent updated"));
+
+        verify(mockOFAgentService);
+        verify(mockOFAgentAdminService);
+
+    }
+
+    /**
+     * Tests non-existent OFAgent updating with PUT.
+     */
+    @Test
+    public void testNonExistentOFAgentUpdate() {
+        expect(mockOFAgentService.agent(anyObject())).andReturn(null).anyTimes();
+        replay(mockOFAgentService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("put-non-existent-ofagent-update.json");
+        assertNotNull("put-non-existent-ofagent-update.json is null", jsonStream);
+        WebTarget wt = target();
+        Response response = wt.path("service/ofagent-update")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .put(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND));
+
+        verify(mockOFAgentService);
+
+    }
+
+    /**
+     * Tests OFAgent updating with bad PUT request.
+     */
+    @Test
+    public void testOFAgentUpdateBadRequest() {
+        expect(mockOFAgentService.agent(anyObject())).andReturn(null).anyTimes();
+        replay(mockOFAgentService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("put-bad-request.json");
+        assertNotNull("put-bad-request.json is null", jsonStream);
+        WebTarget wt = target();
+        Response response = wt.path("service/ofagent-update")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .put(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_INTERNAL_ERROR));
+
+        verify(mockOFAgentService);
+    }
+
+    /**
+     * Tests starting an OFAgent with POST.
+     */
+    @Test
+    public void testOFAgentStart() {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes();
+        replay(mockOFAgentService);
+
+        mockOFAgentAdminService.startAgent(anyObject());
+        expectLastCall().anyTimes();
+        replay(mockOFAgentAdminService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-ofagent-start.json");
+        assertNotNull("post-ofagent-create.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-start")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
+//        assertThat(response.readEntity(String.class), containsString("OFAgent started"));
+        assertThat(response.readEntity(String.class), is("OFAgent started"));
+
+        verify(mockOFAgentService);
+        verify(mockOFAgentAdminService);
+    }
+
+    /**
+     * Tests non-existent OFAgent starting with POST.
+     */
+    @Test
+    public void testNonExistentOFAgentStart() {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(null).anyTimes();
+        replay(mockOFAgentService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-non-existent-ofagent-start.json");
+        assertNotNull("post-non-existent-ofagent-start.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-start")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND));
+
+        verify(mockOFAgentService);
+    }
+
+    /**
+     * Tests OFAgent starting with bad POST request.
+     */
+    @Test
+    public void testOFAgentStartBadRequest() {
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-bad-request.json");
+        assertNotNull("post-bad-request.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-start")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
+
+    }
+
+    /**
+     * Tests stopping an OFAgent with POST.
+     */
+    @Test
+    public void testOFAgentStop() {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes();
+        replay(mockOFAgentService);
+
+        mockOFAgentAdminService.stopAgent(anyObject());
+        expectLastCall().anyTimes();
+        replay(mockOFAgentAdminService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-ofagent-stop.json");
+        assertNotNull("post-ofagent-stop.json is null", jsonStream);
+        WebTarget wt = target();
+        Response response = wt.path("service/ofagent-stop")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
+
+        verify(mockOFAgentService);
+        verify(mockOFAgentAdminService);
+    }
+
+    /**
+     * Tests stopping non-existent OFAgent with POST.
+     */
+    @Test
+    public void testNonExistentOFAgentStop() {
+        expect(mockOFAgentService.agent(NETWORK)).andReturn(null).anyTimes();
+        replay(mockOFAgentService);
+
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-non-existent-ofagent-stop.json");
+        assertNotNull("post-non-existent-ofagent-stop.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-stop")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND));
+
+        verify(mockOFAgentService);
+    }
+
+    /**
+     * Tests stopping FAgent with bad POST request.
+     */
+    @Test
+    public void testOFAgentStopBadRequest() {
+        InputStream jsonStream = OFAgentWebResourceTest.class
+                .getResourceAsStream("post-bad-request.json");
+        assertNotNull("post-bad-request.json is null", jsonStream);
+        WebTarget wt = target();
+
+        Response response = wt.path("service/ofagent-stop")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_INTERNAL_ERROR));
+    }
+
+
+    /**
+     * Tests deleting an OFAgent with DELETE.
+     */
+    @Test
+    public void testOFAgentRemove() {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes();
+        replay(mockOFAgentService);
+
+        expect(mockOFAgentAdminService.removeAgent(NETWORK)).andReturn(OF_AGENT).anyTimes();
+        replay(mockOFAgentAdminService);
+
+        WebTarget wt = target();
+        Response response = wt.path("service/ofagent-remove/" + NETWORK.toString())
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .delete();
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
+        final JsonObject result = Json.parse(response.readEntity(String.class)).asObject();
+        assertThat(result.get("networkId").asString(), is(NETWORK.id().toString()));
+        assertThat(result.get("state").asString(), is(STOPPED.toString()));
+
+        verify(mockOFAgentService);
+        verify(mockOFAgentAdminService);
+    }
+
+    /**
+     * Tests deleting a non-existent OFAgent with DELETE.
+     */
+    @Test
+    public void testNonExistentOFAgentRemove() {
+        expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(null).anyTimes();
+        replay(mockOFAgentService);
+
+        expect(mockOFAgentAdminService.removeAgent(NETWORK)).andReturn(null).anyTimes();
+        replay(mockOFAgentAdminService);
+
+        WebTarget wt = target();
+        Response response = wt.path("service/ofagent-remove/" + NETWORK.toString())
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .delete();
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
+        assertThat(response.readEntity(String.class), containsString("OFAgent not found"));
+
+        verify(mockOFAgentService);
+        verify(mockOFAgentAdminService);
+    }
+}
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-bad-request.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-bad-request.json
new file mode 100644
index 0000000..7a73a41
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-bad-request.json
@@ -0,0 +1,2 @@
+{
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-start.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-start.json
new file mode 100644
index 0000000..165e0e2
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-start.json
@@ -0,0 +1,3 @@
+{
+  "networkId": "3"
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-stop.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-stop.json
new file mode 100644
index 0000000..165e0e2
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-stop.json
@@ -0,0 +1,3 @@
+{
+  "networkId": "3"
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-create.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-create.json
new file mode 100644
index 0000000..7632bbf
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-create.json
@@ -0,0 +1,9 @@
+{
+  "networkId": "3",
+  "controllers": [
+    {
+      "ip": "147.91.1.27",
+      "port": "63"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-start.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-start.json
new file mode 100644
index 0000000..165e0e2
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-start.json
@@ -0,0 +1,3 @@
+{
+  "networkId": "3"
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-stop.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-stop.json
new file mode 100644
index 0000000..165e0e2
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-stop.json
@@ -0,0 +1,3 @@
+{
+  "networkId": "3"
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-bad-request.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-bad-request.json
new file mode 100644
index 0000000..c3c3d92
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-bad-request.json
@@ -0,0 +1,12 @@
+{
+  "controllers": [
+    {
+      "ip": "147.91.1.27",
+      "port": "6633"
+    },
+    {
+      "ip": "147.91.1.25",
+      "port": "6633"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-non-existent-ofagent-update.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-non-existent-ofagent-update.json
new file mode 100644
index 0000000..86d1b21
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-non-existent-ofagent-update.json
@@ -0,0 +1,13 @@
+{
+  "networkId": "3",
+  "controllers": [
+    {
+      "ip": "147.91.1.27",
+      "port": "6653"
+    },
+    {
+      "ip": "147.91.1.4",
+      "port": "6633"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-ofagent-update.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-ofagent-update.json
new file mode 100644
index 0000000..1a36150
--- /dev/null
+++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-ofagent-update.json
@@ -0,0 +1,13 @@
+{
+  "networkId": "3",
+  "controllers": [
+    {
+      "ip": "147.91.1.27",
+      "port": "6633"
+    },
+    {
+      "ip": "147.91.1.25",
+      "port": "6633"
+    }
+  ]
+}
\ No newline at end of file