Support REST optical intent creation

Change-Id: I3b040ad7a337cb1b145bcbd3d0e5fdb5406334c0
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/cli/AddOpticalIntentCommand.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/cli/AddOpticalIntentCommand.java
index 4bdde84..07f9cc1 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/cli/AddOpticalIntentCommand.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/cli/AddOpticalIntentCommand.java
@@ -23,29 +23,21 @@
 import org.onosproject.cli.net.ConnectPointCompleter;
 import org.onosproject.cli.net.ConnectivityIntentCommand;
 import org.onosproject.net.ChannelSpacing;
-import org.onosproject.net.CltSignalType;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.GridType;
 import org.onosproject.net.OchSignal;
-import org.onosproject.net.OduSignalType;
 import org.onosproject.net.Port;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
-import org.onosproject.net.intent.OpticalCircuitIntent;
-import org.onosproject.net.intent.OpticalConnectivityIntent;
-import org.onosproject.net.intent.OpticalOduIntent;
-import org.onosproject.net.optical.OchPort;
-import org.onosproject.net.optical.OduCltPort;
 
 import java.util.Map;
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
+import static org.onosproject.net.optical.util.OpticalIntentUtility.createOpticalIntent;
 
 /**
  * Installs optical connectivity or circuit intents, depending on given port types.
@@ -152,71 +144,12 @@
     @Override
     protected void execute() {
         IntentService service = get(IntentService.class);
-
+        DeviceService deviceService = get(DeviceService.class);
         ConnectPoint ingress = createConnectPoint(ingressString);
         ConnectPoint egress = createConnectPoint(egressString);
 
-        if (ingress == null || egress == null) {
-            print("Invalid endpoint(s); could not create optical intent");
-            return;
-        }
-
-        DeviceService deviceService = opticalView(get(DeviceService.class));
-
-        Port srcPort = deviceService.getPort(ingress.deviceId(), ingress.port());
-        Port dstPort = deviceService.getPort(egress.deviceId(), egress.port());
-
-        Intent intent;
-
-        if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
-            Device srcDevice = deviceService.getDevice(ingress.deviceId());
-            Device dstDevice = deviceService.getDevice(egress.deviceId());
-
-            // continue only if both OduClt port's Devices are of the same type
-            if (!(srcDevice.type().equals(dstDevice.type()))) {
-                print("Devices without same deviceType: SRC=%s and DST=%s", srcDevice.type(), dstDevice.type());
-                return;
-            }
-
-            CltSignalType signalType = ((OduCltPort) srcPort).signalType();
-            if (Device.Type.ROADM.equals(srcDevice.type()) ||
-                    Device.Type.ROADM_OTN.equals(srcDevice.type())) {
-                intent = OpticalCircuitIntent.builder()
-                        .appId(appId())
-                        .key(key())
-                        .src(ingress)
-                        .dst(egress)
-                        .signalType(signalType)
-                        .bidirectional(bidirectional)
-                        .build();
-            } else if (Device.Type.OTN.equals(srcDevice.type())) {
-                intent = OpticalOduIntent.builder()
-                        .appId(appId())
-                        .key(key())
-                        .src(ingress)
-                        .dst(egress)
-                        .signalType(signalType)
-                        .bidirectional(bidirectional)
-                        .build();
-            } else {
-                print("Wrong Device Type for connect points %s and %s", ingress, egress);
-                return;
-            }
-        } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
-            OduSignalType signalType = ((OchPort) srcPort).signalType();
-            intent = OpticalConnectivityIntent.builder()
-                    .appId(appId())
-                    .key(key())
-                    .src(ingress)
-                    .dst(egress)
-                    .signalType(signalType)
-                    .bidirectional(bidirectional)
-                    .ochSignal(createOchSignal())
-                    .build();
-        } else {
-            print("Unable to create optical intent between connect points %s and %s", ingress, egress);
-            return;
-        }
+        Intent intent = createOpticalIntent(ingress, egress, deviceService,
+                key(), appId(), bidirectional, createOchSignal());
 
         service.submit(intent);
         print("Optical intent submitted:\n%s", intent.toString());
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
new file mode 100644
index 0000000..8deb5ba
--- /dev/null
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.net.optical.util;
+
+import org.onosproject.net.optical.OduCltPort;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.CltSignalType;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.OpticalCircuitIntent;
+import org.onosproject.net.intent.OpticalConnectivityIntent;
+import org.onosproject.net.intent.OpticalOduIntent;
+import org.onosproject.net.optical.OchPort;
+
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
+
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Utility class for optical intents.
+ */
+public final class OpticalIntentUtility {
+
+    private static final Logger log = getLogger(OpticalIntentUtility.class);
+
+    private OpticalIntentUtility() {
+    }
+
+    /**
+     * Returns a new optical intent created from the method parameters.
+     *
+     * @param ingress ingress description (device/port)
+     * @param egress egress description (device/port)
+     * @param deviceService device service
+     * @param key intent key
+     * @param appId application id
+     * @param bidirectional if this argument is true, the optical link created
+     * will be bidirectional, otherwise the link will be unidirectional.
+     * @param signal optical signal
+     *
+     * @return created intent
+     */
+    public static Intent createOpticalIntent(ConnectPoint ingress, ConnectPoint
+            egress, DeviceService deviceService, Key key, ApplicationId appId, boolean
+            bidirectional, OchSignal signal) {
+
+        Intent intent = null;
+
+        if (ingress == null || egress == null) {
+            log.debug("Invalid endpoint(s); could not create optical intent");
+            return intent;
+        }
+
+        DeviceService ds = opticalView(deviceService);
+
+        Port srcPort = ds.getPort(ingress.deviceId(), ingress.port());
+        Port dstPort = ds.getPort(egress.deviceId(), egress.port());
+
+        if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
+            Device srcDevice = ds.getDevice(ingress.deviceId());
+            Device dstDevice = ds.getDevice(egress.deviceId());
+
+            // continue only if both OduClt port's Devices are of the same type
+            if (!(srcDevice.type().equals(dstDevice.type()))) {
+                log.debug("Devices without same deviceType: SRC=%s and DST=%s", srcDevice.type(), dstDevice.type());
+                return intent;
+            }
+
+            CltSignalType signalType = ((OduCltPort) srcPort).signalType();
+            if (Device.Type.ROADM.equals(srcDevice.type()) ||
+                    Device.Type.ROADM_OTN.equals(srcDevice.type())) {
+                intent = OpticalCircuitIntent.builder()
+                        .appId(appId)
+                        .key(key)
+                        .src(ingress)
+                        .dst(egress)
+                        .signalType(signalType)
+                        .bidirectional(bidirectional)
+                        .build();
+            } else if (Device.Type.OTN.equals(srcDevice.type())) {
+                intent = OpticalOduIntent.builder()
+                        .appId(appId)
+                        .key(key)
+                        .src(ingress)
+                        .dst(egress)
+                        .signalType(signalType)
+                        .bidirectional(bidirectional)
+                        .build();
+            } else {
+                log.debug("Wrong Device Type for connect points %s and %s", ingress, egress);
+            }
+        } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
+            OduSignalType signalType = ((OchPort) srcPort).signalType();
+            intent = OpticalConnectivityIntent.builder()
+                    .appId(appId)
+                    .key(key)
+                    .src(ingress)
+                    .dst(egress)
+                    .signalType(signalType)
+                    .bidirectional(bidirectional)
+                    .ochSignal(signal)
+                    .build();
+        } else {
+            log.debug("Unable to create optical intent between connect points %s and %s", ingress, egress);
+        }
+
+        return intent;
+    }
+}
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/util/package-info.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/package-info.java
new file mode 100644
index 0000000..2de4f61
--- /dev/null
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.
+ */
+/**
+ * Optical Network Model utilities.
+ */
+package org.onosproject.net.optical.util;
diff --git a/apps/optical-rest/BUCK b/apps/optical-rest/BUCK
new file mode 100644
index 0000000..9c47cb8
--- /dev/null
+++ b/apps/optical-rest/BUCK
@@ -0,0 +1,35 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//lib:JACKSON',
+    '//lib:javax.ws.rs-api',
+    '//utils/rest:onlab-rest',
+    '//apps/optical-model:onos-apps-optical-model'
+]
+
+APPS = [
+    'org.onosproject.optical-model',
+]
+
+TEST_DEPS = [
+    '//lib:TEST_REST',
+    '//utils/osgi:onlab-osgi-tests',
+    '//web/api:onos-rest-tests',
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+    web_context = '/onos/optical',
+    api_title = 'Optical Network Model REST API',
+    api_version = '1.0',
+    api_description = 'REST API for Optical Model',
+    api_package = 'org.onosproject.net.optical.rest'
+)
+
+onos_app (
+    title = 'Optical Network Model REST API',
+    category = 'Optical',
+    url = 'http://onosproject.org',
+    description = 'This application provides REST support for optical network model.',
+    required_apps = APPS
+)
diff --git a/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java
new file mode 100644
index 0000000..d803fe1
--- /dev/null
+++ b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.net.optical.rest;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.onlab.util.Tools.nullIsNotFound;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.optical.json.OchSignalCodec;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+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.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import static org.onosproject.net.optical.util.OpticalIntentUtility.createOpticalIntent;
+
+/**
+ * Query, submit and withdraw optical network intents.
+ */
+@Path("intents")
+public class OpticalIntentsWebResource extends AbstractWebResource {
+
+    private static final Logger log = getLogger(OpticalIntentsWebResource.class);
+
+    private static final String JSON_INVALID = "Invalid json input";
+
+    private static final String APP_ID = "appId";
+
+    private static final String INGRESS_POINT = "ingressPoint";
+    private static final String EGRESS_POINT = "egressPoint";
+
+    private static final String BIDIRECTIONAL = "bidirectional";
+
+    private static final String SIGNAL = "signal";
+
+    protected static final String MISSING_MEMBER_MESSAGE =
+            " member is required";
+    private static final String E_APP_ID_NOT_FOUND =
+            "Application ID is not found";
+
+    @Context
+    private UriInfo uriInfo;
+
+    /**
+     * Submits a new optical intent.
+     * Creates and submits optical intents from the JSON request.
+     *
+     * @param stream input JSON
+     * @return status of the request - CREATED if the JSON is correct,
+     * BAD_REQUEST if the JSON is invalid
+     * @onos.rsModel CreateIntent
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createIntent(InputStream stream) {
+        try {
+            IntentService service = get(IntentService.class);
+            ObjectNode root = (ObjectNode) mapper().readTree(stream);
+            Intent intent = decode(root);
+            service.submit(intent);
+            UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
+                    .path("intents")
+                    .path(intent.appId().name())
+                    .path(Long.toString(intent.id().fingerprint()));
+            return Response
+                    .created(locationBuilder.build())
+                    .build();
+        } catch (IOException ioe) {
+            throw new IllegalArgumentException(ioe);
+        }
+    }
+
+    private Intent decode(ObjectNode json) {
+        JsonNode ingressJson = json.get(INGRESS_POINT);
+        if (!ingressJson.isObject()) {
+            throw new IllegalArgumentException(JSON_INVALID);
+        }
+
+        ConnectPoint ingress = codec(ConnectPoint.class).decode((ObjectNode) ingressJson, this);
+
+        JsonNode egressJson = json.get(EGRESS_POINT);
+        if (!egressJson.isObject()) {
+            throw new IllegalArgumentException(JSON_INVALID);
+        }
+
+        ConnectPoint egress = codec(ConnectPoint.class).decode((ObjectNode) egressJson, this);
+
+        JsonNode bidirectionalJson = json.get(BIDIRECTIONAL);
+        boolean bidirectional = bidirectionalJson != null ? bidirectionalJson.asBoolean() : false;
+
+        JsonNode signalJson = json.get(SIGNAL);
+        OchSignal signal = null;
+        if (signalJson != null) {
+            if (!signalJson.isObject()) {
+                throw new IllegalArgumentException(JSON_INVALID);
+            } else {
+                signal = OchSignalCodec.decode((ObjectNode) signalJson);
+            }
+        }
+
+        String appIdString = nullIsIllegal(json.get(APP_ID), APP_ID + MISSING_MEMBER_MESSAGE).asText();
+        CoreService service = getService(CoreService.class);
+        ApplicationId appId = nullIsNotFound(service.getAppId(appIdString), E_APP_ID_NOT_FOUND);
+        Key key = null;
+        DeviceService deviceService = get(DeviceService.class);
+
+        return createOpticalIntent(ingress, egress, deviceService, key, appId, bidirectional, signal);
+    }
+}
diff --git a/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalWebApplication.java b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalWebApplication.java
new file mode 100644
index 0000000..9dda793
--- /dev/null
+++ b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalWebApplication.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.net.optical.rest;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * Optical Model Web application.
+ */
+public class OpticalWebApplication extends AbstractWebApplication {
+    @Override
+    public Set<Class<?>> getClasses() {
+        return getClasses(OpticalIntentsWebResource.class);
+    }
+}
diff --git a/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/package-info.java b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/package-info.java
new file mode 100644
index 0000000..5cbbe16
--- /dev/null
+++ b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Optical Network Model REST API.
+ */
+package org.onosproject.net.optical.rest;
diff --git a/apps/optical-rest/src/main/resources/definitions/CreateIntent.json b/apps/optical-rest/src/main/resources/definitions/CreateIntent.json
new file mode 100644
index 0000000..71ef183
--- /dev/null
+++ b/apps/optical-rest/src/main/resources/definitions/CreateIntent.json
@@ -0,0 +1,85 @@
+{
+  "type": "object",
+  "title": "createIntent",
+  "required": [
+    "ingressPoint",
+    "egressPoint"
+  ],
+  "properties": {
+    "appId": {
+      "type": "string",
+      "example": "org.onosproject.ovsdb"
+    },
+    "ingressPoint": {
+      "type": "object",
+      "title": "ingressPoint",
+      "required": [
+        "device",
+        "port"
+      ],
+      "properties": {
+        "device": {
+          "type": "string",
+          "example": "of:0000000000000001" 
+        },
+        "port": {
+          "type": "string",
+          "example": "1" 
+        }
+      }
+    },
+    "egressPoint": {
+      "type": "object",
+      "title": "egressPoint",
+      "required": [
+        "device",
+        "port"
+      ],
+      "properties": {
+        "device": {
+          "type": "string",
+          "example": "of:0000000000000002"
+        },
+        "port": {
+          "type": "string",
+          "example": "200"
+        }
+      }
+    },
+    "bidirection": {
+      "type": "boolean",
+      "example": true
+    },
+    "signal": {
+      "type": "object",
+      "title": "signal",
+      "required": [
+        "channelSpacing",
+        "gridType",
+        "spacingMultiplier",
+        "slotGranularity"
+      ],
+      "properties": {
+        "channelSpacing": {
+          "type": "string",
+          "example": "6.25"
+        },
+        "gridType": {
+          "type": "string",
+          "enum": ["dwdm", "cwdm", "flex"],
+          "example": "flex"
+        },
+        "spacingMultiplier": {
+          "type": "integer",
+          "format": "int32",
+          "example": 1
+        },
+        "slotGranularity": {
+          "type": "integer",
+          "format": "int32",
+          "example": 1
+        }
+      }
+    }
+  }
+}
diff --git a/apps/optical-rest/src/main/webapp/WEB-INF/web.xml b/apps/optical-rest/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..1437d86
--- /dev/null
+++ b/apps/optical-rest/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Foundation
+  ~
+  ~ 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>Optical Network Model REST API</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.net.optical.rest.OpticalWebApplication</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/modules.defs b/modules.defs
index 63afd14..00f828d 100644
--- a/modules.defs
+++ b/modules.defs
@@ -164,6 +164,7 @@
     '//apps/mobility:onos-apps-mobility-oar',
     '//apps/newoptical:onos-apps-newoptical-oar',
     '//apps/optical-model:onos-apps-optical-model-oar',
+    '//apps/optical-rest:onos-apps-optical-rest-oar',
     '//apps/pathpainter:onos-apps-pathpainter-oar',
     '//apps/pcep-api:onos-apps-pcep-api-oar',
     '//apps/pim:onos-apps-pim-oar',