RESTCONF Server outline

Change-Id: Id93a647b35b24c47f2828763a799b56a50113faf
diff --git a/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfProtocolProxy.java b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfProtocolProxy.java
new file mode 100644
index 0000000..35a35e9
--- /dev/null
+++ b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfProtocolProxy.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016-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.protocol.restconf.server.rpp;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * RESTCONF Server front-end application.
+ */
+public class RestconfProtocolProxy extends AbstractWebApplication {
+
+    @Override
+    public Set<Class<?>> getClasses() {
+        return getClasses(RestconfWebResource.class);
+    }
+}
diff --git a/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java
new file mode 100644
index 0000000..f2608a3
--- /dev/null
+++ b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2016-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.protocol.restconf.server.rpp;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.glassfish.jersey.server.ChunkedOutput;
+import org.onosproject.protocol.restconf.server.api.RestconfException;
+import org.onosproject.protocol.restconf.server.api.RestconfService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+
+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.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/*
+ * This class is the main implementation of the RESTCONF Protocol
+ * Proxy module. Currently it only handles some basic operations
+ * on data resource nodes. However, the design intention is to
+ * create a code structure that allows new methods/functionality
+ * to be easily added in future releases.
+ */
+
+/**
+ * Implementation of the RESTCONF Protocol Proxy module.
+ */
+@Path("/")
+public class RestconfWebResource extends AbstractWebResource {
+
+    @Context
+    UriInfo uriInfo;
+
+    private final RestconfService service = get(RestconfService.class);
+    private final Logger log = getLogger(getClass());
+
+    /**
+     * Handles a RESTCONF GET operation against a target data resource. If the
+     * operation is successful, the JSON presentation of the resource plus HTTP
+     * status code "200 OK" is returned. Otherwise, HTTP error status code
+     * "400 Bad Request" is returned.
+     *
+     * @param uriString URI of the data resource.
+     * @return HTTP response
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("data/{identifier : .+}")
+    public Response handleGetRequest(@PathParam("identifier") String uriString) {
+
+        log.debug("handleGetRequest: {}", uriString);
+
+        try {
+            ObjectNode node = service.runGetOperationOnDataResource(uriString);
+            return ok(node).build();
+        } catch (RestconfException e) {
+            log.error("ERROR: handleGetRequest: {}", e.getMessage());
+            log.debug("Exception in handleGetRequest:", e);
+            return e.getResponse();
+        }
+    }
+
+    /**
+     * Handles the RESTCONF Event Notification Subscription request. If the
+     * subscription is successful, a ChunkedOutput stream is created and returned
+     * to the caller.
+     * <P></P>
+     * This function is not blocked on streaming the data (so that it can handle
+     * other incoming requests). Instead, a worker thread running in the background
+     * does the data streaming. If errors occur during streaming, the worker thread
+     * calls ChunkedOutput.close() to disconnect the session and terminates itself.
+     *
+     * @param streamId Event stream ID
+     * @return A string data stream over HTTP keep-alive session
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("streams/{streamId}")
+    public ChunkedOutput<String> handleNotificationRegistration(@PathParam("streamId") String streamId) {
+        final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class);
+        try {
+            service.subscribeEventStream(streamId, output);
+        } catch (RestconfException e) {
+            log.error("ERROR: handleNotificationRegistration: {}", e.getMessage());
+            log.debug("Exception in handleNotificationRegistration:", e);
+            try {
+                output.close();
+            } catch (IOException ex) {
+                log.error("ERROR: handleNotificationRegistration:", ex);
+            }
+        }
+
+        return output;
+    }
+
+    /**
+     * Handles a RESTCONF POST operation against a data resource. If the
+     * operation is successful, HTTP status code "201 Created" is returned
+     * and there is no response message-body. If the data resource already
+     * exists, then the HTTP status code "409 Conflict" is returned.
+     *
+     * @param uriString URI of the data resource
+     * @param stream    Input JSON object
+     * @return HTTP response
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("data/{identifier : .+}")
+    public Response handlePostRequest(@PathParam("identifier") String uriString, InputStream stream) {
+
+        log.debug("handlePostRequest: {}", uriString);
+
+        try {
+            ObjectNode rootNode = (ObjectNode) mapper().readTree(stream);
+
+            service.runPostOperationOnDataResource(uriString, rootNode);
+            return Response.created(uriInfo.getRequestUri()).build();
+        } catch (JsonProcessingException e) {
+            log.error("ERROR: handlePostRequest ", e);
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        } catch (RestconfException e) {
+            log.error("ERROR: handlePostRequest: {}", e.getMessage());
+            log.debug("Exception in handlePostRequest:", e);
+            return e.getResponse();
+        } catch (IOException ex) {
+            log.error("ERROR: handlePostRequest ", ex);
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        }
+    }
+
+    /**
+     * Handles a RESTCONF PUT operation against a data resource. If a new
+     * resource is successfully created, then the HTTP status code "201 Created"
+     * is returned. If an existing resource is modified, then the HTTP
+     * status code "204 No Content" is returned. If the input JSON payload
+     * contains errors, then "400 Bad Request" is returned. If an exception
+     * occurs during the operation, the status code enclosed in
+     * the RestconfException object, such as "500 Internal Server Error",
+     * is returned.
+     *
+     * @param uriString URI of the data resource.
+     * @param stream    Input JSON object
+     * @return HTTP response
+     */
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("data/{identifier : .+}")
+    public Response handlePutRequest(@PathParam("identifier") String uriString, InputStream stream) {
+
+        log.debug("handlePutRequest: {}", uriString);
+
+        try {
+            ObjectNode rootNode = (ObjectNode) mapper().readTree(stream);
+
+            service.runPutOperationOnDataResource(uriString, rootNode);
+            return Response.created(uriInfo.getRequestUri()).build();
+        } catch (JsonProcessingException e) {
+            log.error("ERROR: handlePutRequest ", e);
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        } catch (RestconfException e) {
+            log.error("ERROR: handlePutRequest: {}", e.getMessage());
+            log.debug("Exception in handlePutRequest:", e);
+            return e.getResponse();
+        } catch (IOException ex) {
+            log.error("ERROR: handlePutRequest ", ex);
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        }
+    }
+
+    /**
+     * Handles the RESTCONF DELETION Operation against a data resource. If the
+     * resource is successfully deleted, the HTTP status code "204 No Content"
+     * is returned in the response. If an exception occurs, then the
+     * HTTP status code enclosed in the RestconfException object is
+     * returned.
+     *
+     * @param uriString URI of the data resource to be deleted.
+     * @return HTTP response
+     */
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("data/{identifier : .+}")
+    public Response handleDeleteRequest(@PathParam("identifier") String uriString) {
+
+        log.debug("handleDeleteRequest: {}", uriString);
+
+        try {
+            service.runDeleteOperationOnDataResource(uriString);
+            return Response.ok().build();
+        } catch (RestconfException e) {
+            log.error("ERROR: handleDeleteRequest: {}", e.getMessage());
+            log.debug("Exception in handleDeleteRequest:", e);
+            return e.getResponse();
+        }
+    }
+
+}
diff --git a/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/package-info.java b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/package-info.java
new file mode 100644
index 0000000..01f56f2
--- /dev/null
+++ b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-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.
+ */
+
+/**
+ * RESTCONF Protocol Proxy implementation.
+ */
+package org.onosproject.protocol.restconf.server.rpp;
diff --git a/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml b/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..c738da9
--- /dev/null
+++ b/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016-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>ONOS RESTCONF Protocol Proxy</display-name>
+
+    <servlet>
+        <servlet-name>RESTCONF Protocol Proxy</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.protocol.restconf.server.rpp.RestconfProtocolProxy</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>RESTCONF Protocol Proxy</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>