ONOS-7827 TAPI Phot. OpticalConnectivity intent.

Change-Id: I34bcc2a2bce4dbd6cca5c99f96e78cee0a53d690
diff --git a/apps/odtn/service/BUILD b/apps/odtn/service/BUILD
index d8cd167..abf6ee6 100644
--- a/apps/odtn/service/BUILD
+++ b/apps/odtn/service/BUILD
@@ -3,6 +3,7 @@
     "//apps/config:onos-apps-config",
     "//models/tapi:onos-models-tapi",
     "//apps/yang:onos-apps-yang",
+    "//apps/optical-model:onos-apps-optical-model",
     "//protocols/netconf/api:onos-protocols-netconf-api",
 ]
 
@@ -24,6 +25,7 @@
     "org.onosproject.drivers.netconf",  # will need if using TemplateManager
     "org.onosproject.drivers.odtn-driver",
     "org.onosproject.netconf",
+    "org.onosproject.optical-model",
     "org.onosproject.configsync-netconf",
     "org.onosproject.protocols.restconfserver",
 ]
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/TapiConnectivityConfig.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/TapiConnectivityConfig.java
new file mode 100644
index 0000000..580dd2a
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/TapiConnectivityConfig.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018-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.odtn;
+
+import org.onosproject.net.ConnectPoint;
+import java.util.Objects;
+
+/**
+ * Configuration related to a TAPI Connectivity.
+ *
+ * At this point, the class only conveys the
+ * Connectivity service uuid, the ConnectPoints
+ * obtained from the TAPI SIP and a boolean that
+ * means setup or release. Additional attributes
+ * may be needed when we further parse the TAPI
+ * request, this class will grow accordingly.
+ */
+public final class TapiConnectivityConfig {
+
+    private final String uuid;
+    private final ConnectPoint left;
+    private final ConnectPoint right;
+    private final boolean setup;
+
+
+    /**
+     * Constructor with the Connection uuid and endpoints.
+     *
+     * @param uuid - TAPI uuid of the connection.
+     * @param leftCp Left (ingress) ConnectPoint.
+     * @param rightCp Right (egress) ConnectPoint.
+     * @param setup True or false (setup or release).
+     */
+    public TapiConnectivityConfig(String uuid, ConnectPoint leftCp,
+        ConnectPoint rightCp, Boolean setup) {
+        this.uuid = uuid;
+        this.left = leftCp;
+        this.right = rightCp;
+        this.setup = setup;
+    }
+
+    /**
+     * Get the UUID associated to this TAPI connectivity rquest.
+     *
+     * @return the UUID.
+     */
+    public String uuid() {
+        return uuid;
+    }
+
+
+    /**
+     * Get the left (first) ConnectPoint of the request.
+     * The left CP corresponds to the first endpoint in the TAPI
+     * request.
+     *
+     * @return the connect point.
+     */
+    public ConnectPoint leftCp() {
+        return left;
+    }
+
+
+    /**
+     * Get the right (second) ConnectPoint of the request.
+     * The right CP corresponds to the second endpoint in the TAPI
+     * request.
+     *
+     * @return the connect point.
+     */
+    public ConnectPoint rightCp() {
+        return right;
+    }
+
+    /**
+     * Check if the request is for a setup or release.
+     *
+     * @return True for a setup request, False otherwise.
+     */
+    public Boolean isSetup() {
+        return setup;
+    }
+
+
+    /**
+     * Equals comparison.
+     *
+     * @return True if this:Object.equals(o)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof TapiConnectivityConfig)) {
+            return false;
+        }
+        TapiConnectivityConfig that = (TapiConnectivityConfig) o;
+        return Objects.equals(uuid, that.uuid) &&
+            Objects.equals(left, that.left) &&
+            Objects.equals(right, that.right) &&
+            Objects.equals(setup, that.setup);
+    }
+
+
+    /**
+     * Get the hashcode for the TapiConnectivityConfig Object.
+     *
+     * @return the result of Objects.hash
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hash(uuid, left, right, setup);
+    }
+}
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/TapiConnectivityService.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/TapiConnectivityService.java
new file mode 100644
index 0000000..1c4fb18
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/TapiConnectivityService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018-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.odtn;
+
+/**
+ * TAPI ConnectivityService Processor.
+ */
+public interface TapiConnectivityService {
+
+    /**
+     * Process a Setup or Release of a Connectivity Service.
+     *
+     * @param config TAPI configuration data
+     */
+    void processTapiEvent(TapiConnectivityConfig config);
+
+}
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
index 9e4bed3..e9985c6 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
@@ -25,27 +25,39 @@
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
+
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.Port;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
+
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REMOVED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
+import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
+
+
 import org.onosproject.net.link.LinkEvent;
 import org.onosproject.net.link.LinkListener;
 import org.onosproject.net.link.LinkService;
+
 import org.onosproject.odtn.TapiResolver;
+import org.onosproject.odtn.TapiConnectivityConfig;
+import org.onosproject.odtn.TapiConnectivityService;
 import org.onosproject.odtn.TapiTopologyManager;
 import org.onosproject.odtn.config.TerminalDeviceConfig;
 import org.onosproject.odtn.internal.DcsBasedTapiCommonRpc;
 import org.onosproject.odtn.internal.DcsBasedTapiConnectivityRpc;
-import org.onosproject.odtn.internal.DcsBasedTapiDataProducer;
-import org.onosproject.odtn.internal.TapiDataProducer;
 import org.onosproject.odtn.internal.DefaultOdtnTerminalDeviceDriver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -58,16 +70,33 @@
 
 import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
 import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REMOVED;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
-import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
+
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.OpticalConnectivityIntent;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * OSGi Component for ODTN Service application.
  */
-@Component(immediate = true)
-public class ServiceApplicationComponent {
+@Component(immediate = true, service = TapiConnectivityService.class)
+public class ServiceApplicationComponent implements TapiConnectivityService  {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -78,9 +107,15 @@
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected IntentService intentService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected LinkService linkService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected NetworkConfigService netcfgService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -95,6 +130,12 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected TapiResolver resolver;
 
+    private static final int WITHDRAW_EVENT_TIMEOUT_SECONDS = 5;
+
+    private static final String APP_ID = "org.onosproject.odtn-service";
+
+    private ApplicationId appId;
+
     // Listener for events from the DCS
     private final DynamicConfigListener dynamicConfigServiceListener =
             new InternalDynamicConfigListener();
@@ -102,7 +143,6 @@
     private DeviceListener deviceListener = new InternalDeviceListener();
     private final LinkListener linkListener = new InternalLinkListener();
     private final NetworkConfigListener netcfgListener = new InternalNetCfgListener();
-    private TapiDataProducer dataProvider = new DcsBasedTapiDataProducer();
 
     // Rpc Service for TAPI Connectivity
     private final DcsBasedTapiConnectivityRpc rpcTapiConnectivity = new DcsBasedTapiConnectivityRpc();
@@ -112,16 +152,17 @@
     private final ConfigFactory<ConnectPoint, TerminalDeviceConfig> factory =
             new ConfigFactory<ConnectPoint, TerminalDeviceConfig>(CONNECT_POINT_SUBJECT_FACTORY,
                     TerminalDeviceConfig.class, TerminalDeviceConfig.CONFIG_KEY) {
+
                 @Override
                 public TerminalDeviceConfig createConfig() {
                     return new TerminalDeviceConfig();
                 }
             };
 
-
     @Activate
     protected void activate() {
         log.info("Started");
+        appId = coreService.registerApplication(APP_ID);
         dynConfigService.addListener(dynamicConfigServiceListener);
         deviceService.addListener(deviceListener);
         linkService.addListener(linkListener);
@@ -134,7 +175,6 @@
         rpcTapiCommon.init();
     }
 
-
     @Deactivate
     protected void deactivate() {
         log.info("Stopped");
@@ -149,10 +189,105 @@
 
 
     /**
+     * Process TAPI Event from NBI.
+     *
+     * @param config TAPI Connectivity config for the event
+     */
+    public void processTapiEvent(TapiConnectivityConfig config) {
+        checkNotNull(config, "Config can't be null");
+        Key key = Key.of(config.uuid(), appId);
+        // Setup the Intent
+        if (config.isSetup()) {
+            log.debug("TAPI config: {} to setup intent", config);
+            Intent intent = createOpticalIntent(config.leftCp(), config.rightCp(), key, appId);
+            intentService.submit(intent);
+        } else {
+        // Release the intent
+            Intent intent = intentService.getIntent(key);
+            if (intent == null) {
+                log.error("Intent for uuid {} does not exist", config.uuid());
+                return;
+            }
+            log.debug("TAPI config: {} to purge intent {}", config, intent);
+            CountDownLatch latch = new CountDownLatch(1);
+            IntentListener listener = new DeleteListener(key, latch);
+            intentService.addListener(listener);
+            try {
+                /*
+                 * RCAS: Note, withdraw is asynchronous. We cannot call purge
+                 * directly, because at this point it remains in the "INSTALLED"
+                 * state.
+                 */
+                intentService.withdraw(intent);
+
+                /*
+                 * org.onosproject.onos-core-net - 2.1.0.SNAPSHOT |
+                 * Purge for intent 0x0 is rejected because intent state is INSTALLED
+                 * intentService.purge(intent);
+                 */
+                try {
+                    latch.await(WITHDRAW_EVENT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+                // double check the state
+                IntentState state = intentService.getIntentState(key);
+                if (state == WITHDRAWN || state == FAILED) {
+                    intentService.purge(intent);
+                }
+            } finally {
+                intentService.removeListener(listener);
+            }
+        }
+    }
+
+    /**
+     * Returns a new optical intent created from the method parameters.
+     *
+     * @param ingress ingress description (device/port)
+     * @param egress egress description (device/port)
+     * @param key intent key
+     * @param appId application id. As per Intent class, it cannot be null
+     *
+     * @return created intent
+     */
+    protected Intent createOpticalIntent(ConnectPoint ingress, ConnectPoint egress,
+                                         Key key, ApplicationId appId) {
+        Intent intent = null;
+        if (ingress == null || egress == null) {
+            log.error("Invalid endpoint(s) for optical intent: ingress {}, egress {}",
+                ingress, egress);
+            return null;
+        }
+        DeviceService ds = opticalView(deviceService);
+        Port srcPort = ds.getPort(ingress.deviceId(), ingress.port());
+        Port dstPort = ds.getPort(egress.deviceId(), egress.port());
+        if (srcPort == null || dstPort == null) {
+            log.error("Invalid port(s) for optical intent: src {}, dst {}",
+                srcPort, dstPort);
+            return null;
+        }
+
+        // OchSignal signal = new OchSignal(GridType.FLEX, ChannelSpacing.CHL_6P25GHZ, 1, 1);
+        OchSignal signal = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1);
+        OduSignalType signalType = ((OchPort) srcPort).signalType();
+        intent = OpticalConnectivityIntent.builder()
+            .appId(appId)
+            .key(key)
+            .src(ingress)
+            .dst(egress)
+            .signalType(signalType)
+            .bidirectional(true)
+            .ochSignal(signal)
+            .build();
+        return intent;
+    }
+
+
+    /**
      * Representation of internal listener, listening for device event.
      */
     private class InternalDeviceListener implements DeviceListener {
-
         /**
          * Process an Event from the Device Service.
          *
@@ -188,7 +323,6 @@
      * Representation of internal listener, listening for link event.
      */
     private class InternalLinkListener implements LinkListener {
-
         /**
          * Process an Event from the Device Service.
          *
@@ -212,11 +346,11 @@
         }
     }
 
+
     /**
      * Representation of internal listener, listening for netcfg event.
      */
     private class InternalNetCfgListener implements NetworkConfigListener {
-
         /**
          * Check if the netcfg event should be further processed.
          *
@@ -225,7 +359,6 @@
          */
         @Override
         public boolean isRelevant(NetworkConfigEvent event) {
-
             if (event.type() == CONFIG_ADDED || event.type() == CONFIG_UPDATED) {
                 if (event.config().orElse(null) instanceof TerminalDeviceConfig) {
                     return true;
@@ -246,23 +379,18 @@
          */
         @Override
         public void event(NetworkConfigEvent event) {
-
             log.debug("Event type: {}, subject: {}", event.type(), event.subject());
             DeviceId did = ((ConnectPoint) event.subject()).deviceId();
-
+            TerminalDeviceConfig config = (TerminalDeviceConfig) event.config().get();
             DefaultOdtnTerminalDeviceDriver driver = DefaultOdtnTerminalDeviceDriver.create();
-            TerminalDeviceConfig config;
-
+            log.debug("config: {}", config);
             switch (event.type()) {
                 case CONFIG_ADDED:
                 case CONFIG_UPDATED:
-                    config = (TerminalDeviceConfig) event.config().get();
-                    log.debug("config: {}", config);
                     driver.apply(did, config.clientCp().port(), config.subject().port(), config.isEnabled());
                     break;
+
                 case CONFIG_REMOVED:
-                    config = (TerminalDeviceConfig) event.prevConfig().get();
-                    log.debug("config: {}", config);
                     driver.apply(did, config.clientCp().port(), config.subject().port(), false);
                     break;
                 default:
@@ -271,6 +399,35 @@
         }
     }
 
+
+    /**
+     * Internal listener for tracking the intent deletion events.
+     */
+    private class DeleteListener implements IntentListener {
+        final Key key;
+        final CountDownLatch latch;
+
+        /**
+         * Default constructor.
+         *
+         * @param key   key
+         * @param latch count down latch
+         */
+        DeleteListener(Key key, CountDownLatch latch) {
+            this.key = key;
+            this.latch = latch;
+        }
+
+        @Override
+        public void event(IntentEvent event) {
+            if (Objects.equals(event.subject().key(), key) &&
+                    (event.type() == IntentEvent.Type.WITHDRAWN ||
+                            event.type() == IntentEvent.Type.FAILED)) {
+                latch.countDown();
+            }
+        }
+    }
+
     /**
      * Representation of internal listener, listening for dynamic config event.
      */
@@ -301,69 +458,7 @@
         @Override
         public void event(DynamicConfigEvent event) {
             resolver.makeDirty();
-//            ResourceId rsId = event.subject();
-//            DataNode node;
-//            try {
-//                Filter filter = Filter.builder().addCriteria(rsId).build();
-//                node = dynConfigService.readNode(rsId, filter);
-//            } catch (FailedException e) {
-//                node = null;
-//            }
-//            switch (event.type()) {
-//                case NODE_ADDED:
-//                    onDcsNodeAdded(rsId, node);
-//                    break;
-//
-//                case NODE_DELETED:
-//                    onDcsNodeDeleted(node);
-//                    break;
-//
-//                default:
-//                    log.warn("Unknown Event", event.type());
-//                    break;
-//            }
         }
-
-//        /**
-//         * Process the event that a node has been added to the DCS.
-//         *
-//         * @param rsId ResourceId of the added node
-//         * @param node added node. Access the key and value
-//         */
-//        private void onDcsNodeAdded(ResourceId rsId, DataNode node) {
-//
-//            switch (node.type()) {
-//                case SINGLE_INSTANCE_NODE:
-//                    break;
-//                case MULTI_INSTANCE_NODE:
-//                    break;
-//                case SINGLE_INSTANCE_LEAF_VALUE_NODE:
-//                    break;
-//                case MULTI_INSTANCE_LEAF_VALUE_NODE:
-//                    break;
-//                default:
-//                    break;
-//            }
-//
-//            NodeKey dataNodeKey = node.key();
-//            SchemaId schemaId = dataNodeKey.schemaId();
-
-        // Consolidate events
-//            if (!schemaId.namespace().contains("tapi")) {
-//                return;
-//            }
-//            log.info("namespace {}", schemaId.namespace());
-//        }
-
-//        /**
-//         * Process the event that a node has been deleted from the DCS.
-//         *
-//         * @param dataNode data node
-//         */
-//        private void onDcsNodeDeleted(DataNode dataNode) {
-//            // TODO: Implement release logic
-//        }
-
     }
 
 }
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java
index b585506..daf31e1 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java
@@ -22,8 +22,9 @@
 
 import java.util.concurrent.atomic.AtomicReference;
 import org.onosproject.config.FailedException;
-import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.odtn.TapiResolver;
+import org.onosproject.odtn.TapiConnectivityConfig;
+import org.onosproject.odtn.TapiConnectivityService;
 import org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery;
 import org.onosproject.odtn.utils.tapi.DcsBasedTapiObjectRefFactory;
 import org.onosproject.odtn.utils.tapi.TapiCepPair;
@@ -32,6 +33,11 @@
 import org.onosproject.odtn.utils.tapi.TapiCepRefHandler;
 import org.onosproject.odtn.utils.tapi.TapiConnectionHandler;
 
+import org.onosproject.yang.gen.v1.tapiconnectivity.rev20181210.tapiconnectivity.connectivitycontext.DefaultConnection;
+import org.onosproject.yang.gen.v1.tapiconnectivity.rev20181210.tapiconnectivity.connection.ConnectionEndPoint;
+
+import org.onosproject.net.ConnectPoint;
+
 import org.onosproject.odtn.utils.tapi.TapiNepRef;
 import org.onosproject.odtn.utils.tapi.TapiRouteHandler;
 import org.slf4j.Logger;
@@ -39,55 +45,108 @@
 
 import static org.onlab.osgi.DefaultServiceDirectory.getService;
 
+
+
 /**
  * DCS-dependent Tapi connection manager implementation.
  */
 public final class DcsBasedTapiConnectionManager implements TapiConnectionManager {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
+
     protected TapiPathComputer connectionController;
     private TapiResolver resolver;
-    private NetworkConfigService netcfgService;
+    private TapiConnectivityService processor;
 
     private List<DcsBasedTapiConnectionManager> connectionManagerList = new ArrayList<>();
     private TapiConnection connection = null;
     private TapiConnectionHandler connectionHandler = TapiConnectionHandler.create();
     private Operation op = null;
 
-
     enum Operation {
         CREATE,
         DELETE
     }
 
     private DcsBasedTapiConnectionManager() {
+        connectionController = DefaultTapiPathComputer.create();
+        resolver = getService(TapiResolver.class);
+        processor = getService(TapiConnectivityService.class);
     }
 
     public static DcsBasedTapiConnectionManager create() {
-        DcsBasedTapiConnectionManager self = new DcsBasedTapiConnectionManager();
-        self.connectionController = DefaultTapiPathComputer.create();
-        self.resolver = getService(TapiResolver.class);
-        self.netcfgService = getService(NetworkConfigService.class);
-        return self;
+        return new DcsBasedTapiConnectionManager();
     }
 
+
     @Override
     public TapiConnectionHandler createConnection(TapiNepPair neps) {
 
         // Calculate route
         TapiConnection connection = connectionController.pathCompute(neps);
-        log.info("Calculated path: {}", connection);
-
+        log.debug("Calculated path: {}", connection);
         createConnectionRecursively(connection);
+
+        /*
+         * RCAS Create Intent: Assume that if the result of the pathCompute is flat
+         * and there are no lower connections, it has to be mapped to an intent
+         * It is a connection between line ports (OCh) with an OpticalConnectivity
+         * Intent.
+         */
+        if (connection.getLowerConnections().isEmpty()) {
+            TapiNepRef left  = neps.left();
+            TapiNepRef right = neps.right();
+            ConnectPoint leftConnectPoint = left.getConnectPoint();
+            ConnectPoint rightConnectPoint = right.getConnectPoint();
+            log.debug("Creating Intent from {} to {} {}",
+                leftConnectPoint,
+                rightConnectPoint,
+                connectionHandler.getId());
+            notifyTapiConnectivityChange(connectionHandler.getId().toString(),
+                leftConnectPoint,
+                rightConnectPoint,
+                true);
+        }
         return connectionHandler;
     }
 
     @Override
     public void deleteConnection(TapiConnectionHandler connectionHandler) {
+        // Retrieve the target to be deleted (right now we have the uuid)
+        connectionHandler.read();
 
+        // Remove Intent if exists
+        if (connectionHandler.getLowerConnections().isEmpty()) {
+            // Connection object
+            DefaultConnection connection = connectionHandler.getModelObject();
+            // These are two connection.ConnectionEndpoint (Actually Refs, mainly UUID)
+            ConnectionEndPoint cepLeft  = connection.connectionEndPoint().get(0);
+            ConnectionEndPoint cepRight = connection.connectionEndPoint().get(1);
+
+            TapiNepRef left = TapiNepRef.create(
+                    cepLeft.topologyUuid().toString(),
+                    cepLeft.nodeUuid().toString(),
+                    cepLeft.nodeEdgePointUuid().toString());
+
+            TapiNepRef right = TapiNepRef.create(
+                    cepRight.topologyUuid().toString(),
+                    cepRight.nodeUuid().toString(),
+                    cepRight.nodeEdgePointUuid().toString());
+
+            // update with latest data in DCS
+            left = resolver.getNepRef(left);
+            right = resolver.getNepRef(right);
+            log.debug("Removing intent connection: {}", connection);
+            notifyTapiConnectivityChange(
+                connectionHandler.getId().toString(),
+                left.getConnectPoint(),
+                right.getConnectPoint(),
+                false);
+        }
         deleteConnectionRecursively(connectionHandler);
     }
 
+
     @Override
     public void apply() {
         connectionManagerList.forEach(DcsBasedTapiConnectionManager::apply);
@@ -106,6 +165,8 @@
         }
     }
 
+
+
     /**
      * Emit NetworkConfig event with parameters for device config,
      * to notify configuration change to device drivers.
@@ -137,6 +198,16 @@
         eventEmitter.emit(line.get(), client.get(), enable);
     }
 
+
+
+    /**
+     * Request Application to setup / release Intent.
+     */
+    private void notifyTapiConnectivityChange(String uuid, ConnectPoint left, ConnectPoint right, boolean enable) {
+        TapiConnectivityConfig cfg = new TapiConnectivityConfig(uuid, left, right, enable);
+        processor.processTapiEvent(cfg);
+    }
+
     /**
      * Generate TAPI connection and its under connections recursively
      * and add them to creation queue.
@@ -179,10 +250,7 @@
         op = Operation.DELETE;
         connectionManagerList.clear();
 
-        // read target to be deleted
-        connectionHandler.read();
         log.info("model: {}", connectionHandler.getModelObject());
-
         this.connection = TapiConnection.create(
                 TapiCepPair.create(
                         DcsBasedTapiObjectRefFactory.create(connectionHandler.getCeps().get(0)),
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectivityRpc.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectivityRpc.java
index 82c8ee2..d5f2962 100755
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectivityRpc.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectivityRpc.java
@@ -65,6 +65,7 @@
         resolver = getService(TapiResolver.class);
     }
 
+
     /**
      * Service interface of createConnectivityService.
      *
@@ -89,19 +90,21 @@
             List<TapiNepRef> nepRefs = input.getSips().stream()
                     .map(sipId -> resolver.getNepRef(sipId))
                     .collect(Collectors.toList());
-            // for test
-//            Map<String, String> filter = new HashMap<>();
-//            filter.put(ODTN_PORT_TYPE, OdtnDeviceDescriptionDiscovery.OdtnPortType.CLIENT.value());
-//            List<TapiNepRef> nepRefs = resolver.getNepRefs(filter);
 
             // setup connections
             TapiNepPair neps = TapiNepPair.create(nepRefs.get(0), nepRefs.get(1));
-            DcsBasedTapiConnectionManager connectionManager = DcsBasedTapiConnectionManager.create();
-            connectionManager.createConnection(neps);
 
-            // setup connectivity service
+            // Allocate a connectivity Service
             TapiConnectivityServiceHandler connectivityServiceHandler = TapiConnectivityServiceHandler.create();
-            connectivityServiceHandler.addConnection(connectionManager.getConnectionHandler().getModelObject().uuid());
+
+            // This connectivity service will be supported over a single end-to-end connection
+            // Allocate a manager for that connection
+            DcsBasedTapiConnectionManager connectionManager = DcsBasedTapiConnectionManager.create();
+            TapiConnectionHandler connectionHandler = connectionManager.createConnection(neps);
+
+            // Add the supporting connection uuid to the service
+            connectivityServiceHandler.addConnection(connectionHandler.getModelObject().uuid());
+
             neps.stream()
                     .map(nepRef -> TapiSepHandler.create().setSip(nepRef.getSipId()))
                     .forEach(sepBuilder -> {
@@ -113,7 +116,9 @@
             connectivityServiceHandler.add();
 
             // output
-            TapiCreateConnectivityOutputHandler output = TapiCreateConnectivityOutputHandler.create()
+            TapiCreateConnectivityOutputHandler output =
+                TapiCreateConnectivityOutputHandler
+                    .create()
                     .addService(connectivityServiceHandler.getModelObject());
             return new RpcOutput(RpcOutput.Status.RPC_SUCCESS, output.getDataNode());
 
@@ -136,17 +141,20 @@
         try {
             TapiDeleteConnectivityInputHandler input = new TapiDeleteConnectivityInputHandler();
             input.setRpcInput(inputVar);
-            log.info("input serviceId: {}", input.getId());
+            log.info("deleteConnectivityService - serviceId: {}", input.getId());
 
+            // Retrieve the Connectivity Service from the DCS, based on Id
             TapiConnectivityServiceHandler serviceHandler = TapiConnectivityServiceHandler.create();
             serviceHandler.setId(input.getId());
-
             DefaultConnectivityService service = serviceHandler.read();
 
+            // For each top-most connection of the service handler, delete that connection
+            // using a manager
             service.connection().stream().forEach(connection -> {
                 TapiConnectionHandler connectionHandler = TapiConnectionHandler.create();
                 connectionHandler.setId(Uuid.fromString(connection.connectionUuid().toString()));
                 DcsBasedTapiConnectionManager manager = DcsBasedTapiConnectionManager.create();
+                log.info("deleteConnectivityService - connectionId: {}", connectionHandler.getId());
                 manager.deleteConnection(connectionHandler);
                 manager.apply();
             });
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiPathComputer.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiPathComputer.java
index f7688cc..c26f26e 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiPathComputer.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiPathComputer.java
@@ -30,6 +30,7 @@
 import static org.onosproject.odtn.utils.tapi.TapiObjectHandler.DEVICE_ID;
 import static org.onosproject.odtn.utils.tapi.TapiObjectHandler.ODTN_PORT_TYPE;
 import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.CONNECTION_ID;
+import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OdtnPortType.LINE;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,7 +65,24 @@
      * as list of Cep pair for each connection to be created
      */
     private TapiConnection pathComputeDetail(TapiNepPair neps) {
-        return mockPathCompute(neps);
+        log.debug("TapiNepPair {}", neps);
+        log.debug("Nep0 {}", neps.left());
+        log.debug("Nep1 {}", neps.right());
+
+        /*
+         * RCAS: 20190117 - We assume that if port type is LINE, it relies on intents.
+         * We construct just a single top-most connection object.
+         */
+        if (neps.left().getPortType() == LINE) {
+            log.info("Connection between line ports");
+            TapiConnection connection = TapiConnection.create(
+                TapiCepRef.create(neps.left(), neps.left().getCepIds().get(0)),
+                TapiCepRef.create(neps.right(), neps.right().getCepIds().get(0))
+                );
+            return connection;
+        } else {
+            return mockPathCompute(neps);
+        }
     }