Reorganizing ODTN app structure

- separated code which could be referenced from drivers

Change-Id: Ic2c0ae0507abc626771dfaf7a8fc18b5a715cc30
diff --git a/apps/odtn/service/BUCK b/apps/odtn/service/BUCK
new file mode 100644
index 0000000..12e6e1e
--- /dev/null
+++ b/apps/odtn/service/BUCK
@@ -0,0 +1,50 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//apps/odtn/api:onos-apps-odtn-api',
+    '//lib:onos-yang-model',
+    '//lib:onos-yang-runtime',
+    '//apps/config:onos-apps-config',
+    '//models/tapi:onos-models-tapi',
+    '//models/openconfig:onos-models-openconfig',
+    '//apps/yang:onos-apps-yang',
+    '//incubator/api:onos-incubator-api',
+    '//lib:org.apache.karaf.shell.console',
+    '//cli:onos-cli',
+    '//lib:JACKSON',
+    '//protocols/netconf/api:onos-protocols-netconf-api'
+]
+
+TEST_DEPS = [
+    '//lib:TEST_ADAPTERS',
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+)
+
+APPS = [
+    'org.onosproject.yang',
+    'org.onosproject.config',
+    'org.onosproject.configsync',
+    'org.onosproject.models.tapi',
+    'org.onosproject.models.openconfig',
+    'org.onosproject.odtn-api'
+
+    # strictly speaking following are not mandatory
+    'org.onosproject.restconf',
+    'org.onosproject.drivers.netconf',# will need if using TemplateManager
+    'org.onosproject.drivers.odtn',
+    'org.onosproject.netconf',
+    'org.onosproject.configsync-netconf',
+    'org.onosproject.protocols.restconfserver',
+]
+
+onos_app (
+    app_name = 'org.onosproject.odtn-service',
+    title = 'ODTN Service Application',
+    category = 'Traffic Steering',
+    url = 'http://onosproject.org',
+    description = 'ODTN Service Application',
+    required_apps = APPS,
+)
diff --git a/apps/odtn/service/pom.xml b/apps/odtn/service/pom.xml
new file mode 100644
index 0000000..d678001
--- /dev/null
+++ b/apps/odtn/service/pom.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2018 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-apps-odtn</artifactId>
+        <version>1.14.0-SNAPSHOT</version>
+    </parent>
+
+
+    <artifactId>onos-apps-odtn-service</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>ONOS ODTN service application</description>
+    <url>http://onosproject.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <onos.version>${project.version}</onos.version>
+        <onos.app.name>org.onosproject.odtn</onos.app.name>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-apps-odtn-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-yang-runtime</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-apps-config</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-models-tapi</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-models-openconfig</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <scope>test</scope>
+            <classifier>tests</classifier>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-protocols-netconf-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-scr-srcdescriptor</id>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <supportedProjectTypes>
+                        <supportedProjectType>bundle</supportedProjectType>
+                        <supportedProjectType>war</supportedProjectType>
+                    </supportedProjectTypes>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.onosproject</groupId>
+                <artifactId>onos-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>cfg</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>cfg</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>swagger</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>swagger</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>app</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>app</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/ModeCompleter.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/ModeCompleter.java
new file mode 100644
index 0000000..f00a3f8
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/ModeCompleter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.cli.impl;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.odtn.cli.impl.OdtnManualTestCommand.Mode;
+
+public class ModeCompleter extends AbstractChoicesCompleter {
+
+    @Override
+    protected List<String> choices() {
+        return Arrays.asList(Mode.values())
+                .stream()
+                .map(Enum::name)
+                .collect(Collectors.toList());
+    }
+}
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
new file mode 100644
index 0000000..1f72785
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
@@ -0,0 +1,227 @@
+/*
+ * 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.cli.impl;
+
+import static org.onosproject.odtn.utils.YangToolUtil.toCharSequence;
+import static org.onosproject.odtn.utils.YangToolUtil.toCompositeData;
+import static org.onosproject.odtn.utils.YangToolUtil.toDocument;
+import static org.onosproject.odtn.utils.YangToolUtil.toResourceData;
+import static org.onosproject.odtn.utils.YangToolUtil.toXmlCompositeStream;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.util.XmlString;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.net.DeviceIdCompleter;
+import org.onosproject.config.DynamicConfigService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.odtn.behaviour.ConfigurableTransceiver;
+import org.onosproject.odtn.behaviour.PlainTransceiver;
+import org.onosproject.odtn.utils.openconfig.OpticalChannel;
+import org.onosproject.odtn.utils.openconfig.Transceiver;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceId;
+import org.slf4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.collect.Lists;
+import com.google.common.io.CharSource;
+
+
+
+@Command(scope = "onos", name = "odtn-manual-test",
+         description = "ODTN manual test command")
+public class OdtnManualTestCommand extends AbstractShellCommand {
+
+    private static final Logger log = getLogger(OdtnManualTestCommand.class);
+
+    public static enum Mode {
+        ENABLE_TRANSCEIVER,
+        DISABLE_TRANSCEIVER,
+        PRECONF_TRANSCEIVER,
+        PRECONF_OPTICAL_CHANNEL,
+    }
+
+    ModeCompleter modeCompleter;
+    @Argument(index = 0, name = "mode", description = "one of Mode see source",
+              required = true)
+    String modeStr = Mode.ENABLE_TRANSCEIVER.name();
+    Mode mode;
+
+    // injecting dependency for OSGi package import generation purpose
+    DeviceIdCompleter uriCompleter;
+    @Option(name = "--deviceId", description = "Device ID URI to send configuration to",
+              required = false)
+    String uri = null;
+
+    // TODO add completer for this?
+    @Option(name = "--component",
+            description = "Component name",
+            required = false, multiValued = false)
+    private String componentName = "TRANSCEIVER_1_1_4_1";
+
+
+    // OSGi Services to be filled in at the beginning.
+    private DynamicConfigService dcs;
+    private DeviceService deviceService;
+
+
+    void printlog(String format, Object... objs) {
+        print(format.replaceAll(Pattern.quote("{}"), "%s"), objs);
+        log.info(format, objs);
+    }
+
+    List<CharSequence> transform(List<DataNode> input) {
+        ResourceId empty = ResourceId.builder().build();
+        return Lists.transform(input,
+                   node -> toCharSequence(toXmlCompositeStream(toCompositeData(toResourceData(empty, node)))));
+    }
+
+
+    @Override
+    protected void execute() {
+        dcs = get(DynamicConfigService.class);
+        deviceService = get(DeviceService.class);
+
+        try {
+            mode = Mode.valueOf(modeStr);
+        } catch (IllegalArgumentException e) {
+            printlog("{} is not a valid Mode, pick one of {}",
+                     modeStr,
+                     Arrays.asList(Mode.values()),
+                     e);
+            return;
+        }
+
+        // effectively configuration context
+        List<CharSequence> nodes = new ArrayList<>();
+
+        // driver selection with fallback to plain OpenConfig
+        DeviceId did = Optional.ofNullable(uri)
+                        .map(DeviceId::deviceId)
+                        .orElse(null);
+        ConfigurableTransceiver transceiver =
+            Optional.ofNullable(did)
+            .map(deviceService::getDevice)
+            .filter(device -> device.is(ConfigurableTransceiver.class))
+            .map(device -> device.as(ConfigurableTransceiver.class))
+            .orElseGet(() -> new PlainTransceiver());
+
+        switch (mode) {
+        case PRECONF_TRANSCEIVER:
+            // note: these doesn't support driver
+            nodes.addAll(transform(Transceiver.preconf(componentName)));
+            break;
+
+        case ENABLE_TRANSCEIVER:
+            nodes.addAll(transceiver.enable(componentName, true));
+            break;
+
+        case DISABLE_TRANSCEIVER:
+            nodes.addAll(transceiver.enable(componentName, false));
+            break;
+
+        case PRECONF_OPTICAL_CHANNEL:
+            // note: these doesn't support driver
+            nodes.addAll(transform(OpticalChannel.preconf(componentName)));
+            break;
+
+        default:
+            printlog("Mode {} not supported yet", mode);
+            break;
+        }
+
+        // Do something about it.
+        doTheMagic(nodes);
+    }
+
+    void doTheMagic(List<CharSequence> nodes) {
+
+        Document doc;
+        try {
+            doc = DocumentBuilderFactory.newInstance()
+                    .newDocumentBuilder().newDocument();
+        } catch (ParserConfigurationException e) {
+            printlog("Unexpected error", e);
+            throw new IllegalStateException(e);
+        }
+
+        // netconf rpc boilerplate part without message-id
+        Element rpc = doc.createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0", "rpc");
+        doc.appendChild(rpc);
+        Element editConfig = doc.createElement("edit-config");
+        rpc.appendChild(editConfig);
+        Element target = doc.createElement("target");
+        editConfig.appendChild(target);
+        target.appendChild(doc.createElement("running"));
+
+        Element config = doc.createElement("config");
+        config.setAttributeNS("http://www.w3.org/2000/xmlns/",
+                            "xmlns:xc",
+                            "urn:ietf:params:xml:ns:netconf:base:1.0");
+        editConfig.appendChild(config);
+
+
+        for (CharSequence node : nodes) {
+            Document ldoc = toDocument(CharSource.wrap(node));
+            Element cfgRoot = ldoc.getDocumentElement();
+
+            // is everything as merge, ok?
+            cfgRoot.setAttribute("xc:operation", "merge");
+
+            // move (or copy) node to another Document
+            config.appendChild(Optional.ofNullable(doc.adoptNode(cfgRoot))
+                                  .orElseGet(() -> doc.importNode(cfgRoot, true)));
+
+            // don't have good use for JSON for now
+            //JsonNode json = toJsonNode(toJsonCompositeStream(toCompositeData(toResourceData(resourceId, node))));
+            //printlog("JSON:\n{}", toCharSequence(json));
+        }
+
+        printlog("XML:\n{}", XmlString.prettifyXml(toCharSequence(doc)));
+
+        // TODO if deviceId is given send it out to the device
+        if (uri != null) {
+            DeviceId deviceId = DeviceId.deviceId(uri);
+            NetconfController ctr = get(NetconfController.class);
+            Optional.ofNullable(ctr.getNetconfDevice(deviceId))
+                .map(NetconfDevice::getSession)
+                .ifPresent(session -> {
+                    try {
+                        session.rpc(toCharSequence(doc, false).toString()).join();
+                    } catch (NetconfException e) {
+                        log.error("Exception thrown", e);
+                    }
+                });
+        }
+    }
+}
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/package-info.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/package-info.java
new file mode 100644
index 0000000..9799fab
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+/**
+ * ODTN CLI commands implementations.
+ */
+package org.onosproject.odtn.cli.impl;
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
new file mode 100644
index 0000000..87ae4f4
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ *
+ *
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ * Contact: Ramon Casellas <ramon.casellas@cttc.es>
+ */
+
+package org.onosproject.odtn.impl;
+
+import java.util.List;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.yang.model.SchemaContextProvider;
+import org.onosproject.yang.runtime.YangRuntimeService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.onosproject.config.DynamicConfigListener;
+import org.onosproject.config.DynamicConfigService;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.Filter;
+import org.onosproject.config.FailedException;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
+
+// import org.onosproject.yang.gen.v1.tapiconnectivity.rev20180216.TapiConnectivity;
+import org.onosproject.yang.gen.v1.tapiconnectivity.rev20180307.TapiConnectivityService;
+
+import org.onosproject.yang.gen.v1.tapiconnectivity.rev20180307.
+    tapiconnectivity.createconnectivityservice.CreateConnectivityServiceInput;
+
+import org.onosproject.yang.gen.v1.tapiconnectivity.rev20180307.
+    tapiconnectivity.createconnectivityservice.createconnectivityserviceinput.EndPoint;
+
+
+
+// onos-yang-tools
+import org.onosproject.yang.model.DataNode;
+
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.DefaultResourceData;
+import org.onosproject.yang.model.ModelObject;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ModelConverter;
+
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.SchemaId;
+
+import org.onosproject.yang.model.RpcRegistry;
+import org.onosproject.yang.model.RpcService;
+import org.onosproject.yang.model.RpcInput;
+import org.onosproject.yang.model.RpcOutput;
+
+
+/**
+ * OSGi Component for ODTN Service application.
+ */
+@Component(immediate = true)
+public class ServiceApplicationComponent {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DynamicConfigService dynConfigService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService netcfgService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected YangRuntimeService yangRuntime;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected SchemaContextProvider schemaContextProvider;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected RpcRegistry rpcRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ModelConverter modelConverter;
+
+
+
+    // Listener for events from the DCS
+    private final DynamicConfigListener dynamicConfigServiceListener =
+        new InternalDynamicConfigListener();
+
+    // Rpc Service for TAPI Connectivity
+    private final RpcService rpcTapiConnectivity =
+        new TapiConnectivityRpc();
+
+
+    @Activate
+    protected void activate() {
+        log.info("Started");
+        dynConfigService.addListener(dynamicConfigServiceListener);
+        rpcRegistry.registerRpcService(rpcTapiConnectivity);
+    }
+
+
+    @Deactivate
+    protected void deactivate() {
+        log.info("Stopped");
+        rpcRegistry.unregisterRpcService(rpcTapiConnectivity);
+        dynConfigService.removeListener(dynamicConfigServiceListener);
+    }
+
+
+
+
+    /**
+     * Representation of internal listener, listening for dynamic config event.
+     */
+    private class InternalDynamicConfigListener implements DynamicConfigListener {
+
+        /**
+         * Check if the DCS event should be further processed.
+         *
+         * @param event config event
+         * @return true if event is supported; false otherwise
+         */
+        @Override
+        public boolean isRelevant(DynamicConfigEvent event) {
+            // Only care about add and delete
+            if ((event.type() != NODE_ADDED) &&
+                (event.type() != NODE_DELETED)) {
+                return false;
+            }
+            return true;
+        }
+
+
+
+
+        /**
+         * Process an Event from the Dynamic Configuration Store.
+         *
+         * @param event config event
+         */
+        @Override
+        public void event(DynamicConfigEvent event) {
+            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();
+            if (!schemaId.namespace().contains("tapi")) {
+                return;
+            }
+
+            // Consolidate events
+            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
+        }
+
+    }
+
+
+
+
+
+    private class TapiConnectivityRpc implements TapiConnectivityService {
+
+
+        /**
+         * Service interface of createConnectivityService.
+         *
+         * @param inputVar input of service interface createConnectivityService
+         * @return rpcOutput output of service interface createConnectivityService
+         */
+        @Override
+        public RpcOutput createConnectivityService(RpcInput inputVar) {
+            DataNode data = inputVar.data();
+            ResourceId rid = inputVar.id();
+
+            log.info("RpcInput Data {}", data);
+            log.info("RpcInput ResourceId {}", rid);
+
+            for (ModelObject mo : getModelObjects(data, rid)) {
+                if (mo instanceof CreateConnectivityServiceInput) {
+                    CreateConnectivityServiceInput i = (CreateConnectivityServiceInput) mo;
+                    log.info("i {}", i);
+                    List<EndPoint> epl = i.endPoint();
+                    for (EndPoint ep : epl) {
+                        log.info("ep {}", ep);
+                    }
+                }
+            }
+
+            return new RpcOutput(RpcOutput.Status.RPC_FAILURE, null);
+        }
+
+
+
+        /**
+         * Service interface of deleteConnectivityService.
+         *
+         * @param inputVar input of service interface deleteConnectivityService
+         * @return rpcOutput output of service interface deleteConnectivityService
+         */
+        @Override
+        public RpcOutput deleteConnectivityService(RpcInput inputVar) {
+            return new RpcOutput(RpcOutput.Status.RPC_FAILURE, null);
+        }
+
+
+
+        /**
+         * Service interface of getConnectionDetails.
+         *
+         * @param inputVar input of service interface getConnectionDetails
+         * @return rpcOutput output of service interface getConnectionDetails
+         */
+        @Override
+        public RpcOutput getConnectionDetails(RpcInput inputVar) {
+            return new RpcOutput(RpcOutput.Status.RPC_FAILURE, null);
+
+        }
+
+        /**
+         * Service interface of getConnectivityServiceList.
+         *
+         * @param inputVar input of service interface getConnectivityServiceList
+         * @return rpcOutput output of service interface getConnectivityServiceList
+         */
+        @Override
+        public RpcOutput getConnectivityServiceList(RpcInput inputVar) {
+            return new RpcOutput(RpcOutput.Status.RPC_FAILURE, null);
+
+        }
+
+        /**
+         * Service interface of getConnectivityServiceDetails.
+         *
+         * @param inputVar input of service interface getConnectivityServiceDetails
+         * @return rpcOutput output of service interface getConnectivityServiceDetails
+         */
+        @Override
+        public RpcOutput getConnectivityServiceDetails(RpcInput inputVar) {
+            return new RpcOutput(RpcOutput.Status.RPC_FAILURE, null);
+
+        }
+
+
+        /**
+         * Service interface of updateConnectivityService.
+         *
+         * @param inputVar input of service interface updateConnectivityService
+         * @return rpcOutput output of service interface updateConnectivityService
+         */
+        @Override
+        public RpcOutput updateConnectivityService(RpcInput inputVar) {
+            return new RpcOutput(RpcOutput.Status.RPC_FAILURE, null);
+
+        }
+
+
+        private ResourceData createResourceData(DataNode dataNode, ResourceId resId) {
+            return DefaultResourceData.builder()
+                .addDataNode(dataNode)
+                .resourceId(resId)
+                .build();
+        }
+
+        /**
+         * Returns model objects of the store.
+         *
+         * @param dataNode data node from store
+         * @param resId    parent resource id
+         * @return model objects
+         */
+        private List<ModelObject> getModelObjects(DataNode dataNode, ResourceId resId) {
+            ResourceData data = createResourceData(dataNode, resId);
+            ModelObjectData modelData = modelConverter.createModel(data);
+            return modelData.modelObjects();
+        }
+
+
+
+    }
+}
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/package-info.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/package-info.java
new file mode 100644
index 0000000..9cb2027
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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 to place ODTN implementations.
+ */
+package org.onosproject.odtn.impl;
diff --git a/apps/odtn/service/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/odtn/service/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 0000000..6611c01
--- /dev/null
+++ b/apps/odtn/service/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ 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.
+  -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+
+        <command>
+            <action class="org.onosproject.odtn.cli.impl.OdtnManualTestCommand"/>
+            <completers>
+                <ref component-id="modeCompleter"/>
+                <null/>
+            </completers>
+            <optional-completers>
+                <entry key="--deviceId" value-ref="deviceIdCompleter"/>
+            </optional-completers>
+        </command>
+
+    </command-bundle>
+
+    <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
+    <bean id="modeCompleter" class="org.onosproject.odtn.cli.impl.ModeCompleter"/>
+
+</blueprint>
\ No newline at end of file
diff --git a/apps/odtn/service/src/test/resources/create-connectivity.json b/apps/odtn/service/src/test/resources/create-connectivity.json
new file mode 100644
index 0000000..283de56
--- /dev/null
+++ b/apps/odtn/service/src/test/resources/create-connectivity.json
@@ -0,0 +1,83 @@
+{
+    "tapi-connectivity:input":
+    {
+        "end-point" : [
+            {
+                "layer-protocol-name" : "DSR",
+                "service-interface-point": {
+                    "service-interface-point-id" : "00000000-0000-4200-0001-110000000000"
+                },
+                "capacity" : {
+                },
+                "direction" : "BIDIRECTIONAL",
+                "role" : "UNKNOWN",
+                "protection-role" : "WORK",
+                "local-id": "00000000-0000-4100-0001-110000000000",
+                "name" : [
+                        {
+                            "value-name" : "port",
+                            "value" : "1"
+                        },
+                        {
+                            "value-name" : "transponder",
+                            "value" : "TRNP_A"
+                        },
+                        {
+                            "value-name" : "onos-index",
+                            "value" : "1"
+                        },
+                        {
+                            "value-name" : "test-driver",
+                            "value" : "driver"
+                        }
+                ],
+                "administrative-state" : "UNLOCKED",
+                "operational-state" : "ENABLED",
+                "lifecycle-state" : "INSTALLED"
+            }
+            ,
+            {
+                "layer-protocol-name" : "DSR",
+                "service-interface-point": {
+                    "service-interface-point-id" : "00000000-0000-4200-0001-210000000000"
+                },
+                "capacity" : {
+                },
+                "direction" : "BIDIRECTIONAL",
+                "role" : "UNKNOWN",
+                "protection-role" : "WORK",
+                "local-id": "00000000-0000-4100-0001-210000000000",
+                "name" : [
+                        {
+                            "value-name" : "port",
+                            "value" : "1"
+                        },
+                        {
+                            "value-name" : "transponder",
+                            "value" : "TRNP_B"
+                        },
+                        {
+                            "value-name" : "onos-index",
+                            "value" : "1"
+                        },
+                        {
+                            "value-name" : "test-driver",
+                            "value" : "driver"
+                        }
+                ],
+                "administrative-state" : "UNLOCKED",
+                "operational-state" : "ENABLED",
+                "lifecycle-state" : "INSTALLED"
+            }
+        ],
+
+        "conn-constraint" : {},
+
+        "topo-constraint" : {},
+
+        "resilience-constraint" : [ ],
+
+        "state" : "operational-state"
+    }
+}
+
diff --git a/apps/odtn/service/src/test/resources/nbi-tapi-sample.json b/apps/odtn/service/src/test/resources/nbi-tapi-sample.json
new file mode 100644
index 0000000..4578336
--- /dev/null
+++ b/apps/odtn/service/src/test/resources/nbi-tapi-sample.json
@@ -0,0 +1,56 @@
+{
+  "tapi-common:context": {
+    "service-interface-point": [
+      {
+        "uuid": "9F759964-2410-44AF-8522-4FCE2C3ED464",
+        "layer-protocol-name": ["DSR"],
+        "name": [
+          {
+            "value-name": "port",
+            "value": "1"
+          },
+          {
+            "value-name": "transponder",
+            "value": "TRPN_A"
+          }
+        ]
+      },
+      {
+        "uuid": "FBDDC006-8913-4509-BA71-485CFAC89567",
+        "layer-protocol-name": ["DSR"],
+        "name": [
+          {
+            "value-name": "port",
+            "value": "1"
+          },
+          {
+            "value-name": "transponder",
+            "value": "TRPN_B"
+          }
+        ]
+      }
+    ],
+
+    "tapi-connectivity:connectivity-service": [
+      {
+        "uuid" : "D0BF25C8-B20C-49C3-9030-1C5AEC993E44",
+        "end-point": [
+          {
+            "local-id" : "TRPN_A-1",
+            "layer-protocol-name": "DSR",
+            "service-interface-point": {
+                "service-interface-point-id" : "9F759964-2410-44AF-8522-4FCE2C3ED464"
+            }
+          },
+          {
+            "local-id" : "TRPN_B-1",
+            "layer-protocol-name": "DSR",
+            "service-interface-point": {
+                "service-interface-point-id" : "FBDDC006-8913-4509-BA71-485CFAC89567"
+            }
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/apps/odtn/service/src/test/resources/post-nbi-tapi-rpc b/apps/odtn/service/src/test/resources/post-nbi-tapi-rpc
new file mode 100644
index 0000000..45bdb17
--- /dev/null
+++ b/apps/odtn/service/src/test/resources/post-nbi-tapi-rpc
@@ -0,0 +1 @@
+curl -X POST http://localhost:8181/onos/restconf/operations/tapi-connectivity:create-connectivity-service -H 'cache-control: no-cache' -H 'content-type: application/json' -d @create-connectivity.json
diff --git a/apps/odtn/service/src/test/resources/post-nbi-tapi-sample b/apps/odtn/service/src/test/resources/post-nbi-tapi-sample
new file mode 100644
index 0000000..ffdd3d9
--- /dev/null
+++ b/apps/odtn/service/src/test/resources/post-nbi-tapi-sample
@@ -0,0 +1,2 @@
+curl -X POST http://localhost:8181/onos/restconf/data -H 'cache-control: no-cache' -H 'content-type: application/json' -d @nbi-tapi-sample.json
+