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
+