Add netconfnode-state-service
v2 add new service to devicemanager
Issue-ID: SDNC-1006
Signed-off-by: herbert <herbert.eiselt@highstreet-technologies.com>
Change-Id: Iaba3d02e0ef6078cba57a33e03c2b2ad7aa0bacd
Signed-off-by: herbert <herbert.eiselt@highstreet-technologies.com>
diff --git a/sdnr/wt/netconfnode-state-service/provider/copyright b/sdnr/wt/netconfnode-state-service/provider/copyright
new file mode 100644
index 0000000..754b621
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/copyright
@@ -0,0 +1,17 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ */
diff --git a/sdnr/wt/netconfnode-state-service/provider/pom.xml b/sdnr/wt/netconfnode-state-service/provider/pom.xml
new file mode 100644
index 0000000..ed0dad7
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ============LICENSE_START=======================================================
+ ONAP : CCSDK / SDNR / WT / netconfnode-state-service
+ ================================================================================
+ Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All
+ rights reserved.
+ ================================================================================
+ 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.
+ ============LICENSE_END=========================================================
+-->
+<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>
+
+ <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+ <artifactId>sdnr-wt-netconfnode-state-service-provider</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ <name>ccsdk-features-sdnr-wt :: ${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <parent>
+ <groupId>org.onap.ccsdk.parent</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>1.5.1-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+
+ <properties>
+ <checkstyle.skip>true</checkstyle.skip> <!-- POM configuration -->
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
+ <buildtime>${maven.build.timestamp} UTC</buildtime>
+ </properties>
+
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+ </license>
+ </licenses>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>sal-netconf-connector</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-common-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-actor_2.12</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-cluster_2.12</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-common</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-netconfnode-state-service-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ </build>
+</project>
+
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java
new file mode 100644
index 0000000..0af35e5
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java
@@ -0,0 +1,586 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.annotation.Nullable;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnectListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateService;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.AkkaConfig;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.GeoConfig;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.NetconfnodeStateServiceRpcApiImpl;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.RpcApigetStateCallback;
+import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.binding.api.MountPoint;
+import org.opendaylight.mdsal.binding.api.MountPointService;
+import org.opendaylight.mdsal.binding.api.NotificationPublishService;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, RpcApigetStateCallback, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class);
+ private static final String APPLICATION_NAME = "NetconfNodeStateService";
+ @SuppressWarnings("unused")
+ private static final String CONFIGURATIONFILE = "etc/netconfnode-status-service.properties";
+
+
+ private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID =
+ InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
+ new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
+
+ private static final InstanceIdentifier<Node> NETCONF_NODE_TOPO_IID =
+ InstanceIdentifier.create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())))
+ .child(Node.class);
+
+ private static final DataTreeIdentifier<Node> NETCONF_NODE_TOPO_TREE_ID =
+ DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID);
+
+ // Name of ODL controller NETCONF instance
+ private static final NodeId CONTROLLER = new NodeId("controller-config");
+
+ // -- OSGi services, provided
+ private DataBroker dataBroker;
+ private MountPointService mountPointService;
+ private RpcProviderService rpcProviderRegistry;
+ @SuppressWarnings("unused")
+ private NotificationPublishService notificationPublishService;
+ @SuppressWarnings("unused")
+ private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+
+ // -- Parameter
+ private ListenerRegistration<L1> listenerL1;
+ private ListenerRegistration<L2> listenerL2;
+ @SuppressWarnings("unused")
+ private ClusterSingletonServiceRegistration cssRegistration;
+
+ private NetconfnodeStateServiceRpcApiImpl rpcApiService;
+
+ /** Indication if init() function called and fully executed **/
+ private Boolean initializationSuccessful;
+
+ /** List of all registered listeners **/
+ private final List<NetconfNodeConnectListener> netconfNodeConnectListenerList;
+
+ /** List of all registered listeners **/
+ private final List<NetconfNodeStateListener> netconfNodeStateListenerList;
+
+ /** List of all registered listeners **/
+ private final List<VesNotificationListener> vesNotificationListenerList;
+
+ /** Indicates if running in cluster configuration **/
+ private boolean isCluster;
+
+ /** Indicates the name of the cluster **/
+ private String clusterName;
+
+ /** Blueprint **/
+ public NetconfNodeStateServiceImpl() {
+ LOG.info("Creating provider for {}", APPLICATION_NAME);
+
+ this.dataBroker = null;
+ this.mountPointService = null;
+ this.rpcProviderRegistry = null;
+ this.notificationPublishService = null;
+ this.clusterSingletonServiceProvider = null;
+
+ this.listenerL1 = null;
+ this.listenerL2 = null;
+ this.initializationSuccessful= false;
+ this.netconfNodeConnectListenerList = new CopyOnWriteArrayList<>();
+ this.netconfNodeStateListenerList = new CopyOnWriteArrayList<>();
+ this.vesNotificationListenerList = new CopyOnWriteArrayList<>();
+ }
+
+ public void setDataBroker(DataBroker dataBroker) {
+ this.dataBroker = dataBroker;
+ }
+
+ public void setRpcProviderRegistry(RpcProviderService rpcProviderRegistry) {
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ }
+
+ public void setNotificationPublishService(NotificationPublishService notificationPublishService) {
+ this.notificationPublishService = notificationPublishService;
+ }
+
+ public void setMountPointService(MountPointService mountPointService) {
+ this.mountPointService = mountPointService;
+ }
+ public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) {
+ this.clusterSingletonServiceProvider = clusterSingletonService;
+ }
+
+ /** Blueprint initialization **/
+ public void init() {
+
+ LOG.info("Session Initiated start {}", APPLICATION_NAME);
+
+ // Start RPC Service
+ this.rpcApiService = new NetconfnodeStateServiceRpcApiImpl(rpcProviderRegistry, vesNotificationListenerList);
+
+ // Get configuration
+ // ConfigurationFileRepresentation config = new ConfigurationFileRepresentation(CONFIGURATIONFILE);
+ // Akka setup
+ AkkaConfig akkaConfig = getAkkaConfig();
+ this.isCluster = akkaConfig == null ? false : akkaConfig.isCluster();
+ this.clusterName = akkaConfig == null ? "" : akkaConfig.getClusterConfig().getClusterSeedNodeName("abc");
+
+ // RPC Service for specific services
+ this.rpcApiService.setStatusCallback(this);
+
+ LOG.debug("start NetconfSubscriptionManager Service");
+ //this.netconfChangeListener = new NetconfChangeListener(this, dataBroker);
+ //this.netconfChangeListener.register();
+ //DataTreeIdentifier<Node> treeId = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID);
+
+ listenerL1 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L1());
+ listenerL2 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L2());
+
+ this.initializationSuccessful = true;
+
+ LOG.info("Session Initiated end. Initialization done {}", initializationSuccessful);
+
+ }
+ /** Blueprint destroy-method method */
+ public void destroy() {
+ close();
+ }
+
+ /**
+ * Getter
+ * @return NetconfnodeStateServiceRpcApiImpl
+ */
+ public NetconfnodeStateServiceRpcApiImpl getNetconfnodeStateServiceRpcApiImpl() {
+ return rpcApiService;
+ }
+
+ @Override
+ public GetStatusOutputBuilder getStatus(GetStatusInput input) {
+ return new GetStatusOutputBuilder();
+ }
+
+ @Override
+ public <L extends NetconfNodeConnectListener> @NonNull ListenerRegistration<L> registerNetconfNodeConnectListener(
+ final @NonNull L netconfNodeConnectListener) {
+ LOG.info("Register connect listener {}",netconfNodeConnectListener.getClass().getName());
+ netconfNodeConnectListenerList.add(netconfNodeConnectListener);
+
+ return new ListenerRegistration<L>() {
+ @Override
+ public @NonNull L getInstance() {
+ return netconfNodeConnectListener;
+ }
+
+ @Override
+ public void close() {
+ LOG.info("Remove connect listener {}",netconfNodeConnectListener);
+ netconfNodeConnectListenerList.remove(netconfNodeConnectListener);
+ }
+ };
+ }
+
+ @Override
+ public <L extends NetconfNodeStateListener> @NonNull ListenerRegistration<L> registerNetconfNodeStateListener(
+ @NonNull L netconfNodeStateListener) {
+ LOG.info("Register state listener {}",netconfNodeStateListener.getClass().getName());
+ netconfNodeStateListenerList.add(netconfNodeStateListener);
+
+ return new ListenerRegistration<L>() {
+ @Override
+ public @NonNull L getInstance() {
+ return netconfNodeStateListener;
+ }
+
+ @Override
+ public void close() {
+ LOG.info("Remove state listener {}",netconfNodeStateListener);
+ netconfNodeStateListenerList.remove(netconfNodeStateListener);
+ }
+ };
+ }
+
+ @Override
+ public <L extends VesNotificationListener> @NonNull ListenerRegistration<L> registerVesNotifications(
+ @NonNull L vesNotificationListener) {
+ LOG.info("Register Ves notification listener {}",vesNotificationListener.getClass().getName());
+ vesNotificationListenerList.add(vesNotificationListener);
+
+ return new ListenerRegistration<L>() {
+ @Override
+ public @NonNull L getInstance() {
+ return vesNotificationListener;
+ }
+
+ @Override
+ public void close() {
+ LOG.info("Remove Ves notification listener {}",vesNotificationListener);
+ vesNotificationListenerList.remove(vesNotificationListener);
+ }
+ };
+ }
+
+ @Override
+ public void close() {
+ LOG.info("Closing start ...");
+ try {
+ close(rpcApiService, listenerL1, listenerL2);
+ } catch (Exception e) {
+ LOG.debug("Closing", e);
+ }
+ LOG.info("Closing done");
+ }
+
+ /**
+ * Used to close all Services, that should support AutoCloseable Pattern
+ *
+ * @param toClose
+ * @throws Exception
+ */
+ private void close(AutoCloseable... toCloseList) throws Exception {
+ for (AutoCloseable element : toCloseList) {
+ if (element != null) {
+ element.close();
+ }
+ }
+ }
+
+ /**
+ * Indication if init() of this bundle successfully done.
+ * @return true if init() was successful. False if not done or not successful.
+ */
+ public boolean isInitializationSuccessful() {
+ return this.initializationSuccessful;
+ }
+
+ /*-------------------------------------------------------------------------------------------
+ * Functions for interface DeviceManagerService
+ */
+
+ /**
+ * For each mounted device a mountpoint is created and this listener is called.
+ * Mountpoint was created or existing. Managed device is now fully connected to node/mountpoint.
+ * @param nNodeId id of the mountpoint
+ * @param netconfNode mountpoint contents
+ */
+ private void enterConnectedState(NodeId nNodeId, NetconfNode netconfNode) {
+
+ String mountPointNodeName = nNodeId.getValue();
+ LOG.info("Starting Event listener on Netconf for mountpoint {}", mountPointNodeName);
+
+ boolean preConditionMissing = false;
+ if (mountPointService == null) {
+ preConditionMissing = true;
+ LOG.warn("No mountservice available.");
+ }
+ if (!initializationSuccessful) {
+ preConditionMissing = true;
+ LOG.warn("Devicemanager initialization still pending.");
+ }
+ if (preConditionMissing) {
+ return;
+ }
+
+ if (isNetconfNodeMaster(netconfNode)) {
+
+ InstanceIdentifier<Node> instanceIdentifier = NETCONF_TOPO_IID.child(Node.class,
+ new NodeKey(new NodeId(mountPointNodeName)));
+
+ Optional<MountPoint> optionalMountPoint = null;
+ int timeout = 10000;
+ while (!(optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier)).isPresent()
+ && timeout > 0) {
+ LOG.info("Event listener waiting for mount point for Netconf device :: Name : {}", mountPointNodeName);
+ sleepMs(1000);
+ timeout -= 1000;
+ }
+
+ if (!optionalMountPoint.isPresent()) {
+ LOG.warn("Event listener timeout while waiting for mount point for Netconf device :: Name : {} ",
+ mountPointNodeName);
+ } else {
+ // Mountpoint is present for sure
+ MountPoint mountPoint = optionalMountPoint.get();
+ // BindingDOMDataBrokerAdapter.BUILDER_FACTORY;
+ LOG.info("Mountpoint with id: {}", mountPoint.getIdentifier());
+
+ Optional<DataBroker> optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class);
+
+ if (!optionalNetconfNodeDatabroker.isPresent()) {
+ LOG.info("Slave mountpoint {} without databroker", mountPointNodeName);
+ } else {
+ LOG.info("Master mountpoint {}", mountPointNodeName);
+ DataBroker netconfNodeDataBroker = optionalNetconfNodeDatabroker.get();
+
+ /*
+ * --> Call Listers for onConnect() Indication
+ for (all)
+ */
+ netconfNodeConnectListenerList.forEach(item -> {
+ try {
+ item.onEnterConnected(nNodeId, netconfNode, netconfNodeDataBroker);
+ } catch (Exception e) {
+ LOG.info("Exception during onEnterConnected listener call", e);
+ }
+ });
+
+ LOG.info("Connect indication forwarded for {}", mountPointNodeName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Leave the connected status to a non connected or removed status
+ * @param action that occurred
+ * @param nNodeId id of the mountpoint
+ * @param nNode mountpoint contents
+ */
+ private void leaveConnectedState(NodeId nNodeId) {
+ LOG.info("netconfNode id {}", nNodeId);
+ netconfNodeConnectListenerList.forEach(item -> {
+ try {
+ if (item != null) {
+ item.onLeaveConnected(nNodeId);
+ } else {
+ LOG.warn("Unexpeced null item during onleave");
+ }
+ } catch (Exception e) {
+ LOG.info("Exception during onLeaveConnected listener call", e);
+ }
+ });
+ }
+
+ // ---- subclasses for listeners
+
+ /**
+ * Clustered listener function to select the right node from
+ * DataObjectModification
+ */
+ private class L1 implements ClusteredDataTreeChangeListener<Node> {
+ @Override
+ public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
+ LOG.info("L1 TreeChange, changes:{}", changes.size());
+
+ for (final DataTreeModification<Node> change : changes) {
+
+ final DataObjectModification<Node> root = change.getRootNode();
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Handle this modificationType:{} path:{} root:{}", root.getModificationType(),
+ change.getRootPath(), root);
+ }
+
+ // Catch potential nullpointer exceptions ..
+ try {
+ ModificationType modificationTyp = root.getModificationType();
+ Node node = modificationTyp == ModificationType.DELETE ? root.getDataBefore()
+ : root.getDataAfter();
+ NodeId nodeId = node != null ? node.getNodeId() : null;
+ if (nodeId != null) {
+ if (nodeId.equals(CONTROLLER)) {
+ // Do not forward any controller related events to devicemanager
+ LOG.debug("Stop processing for [{}]", nodeId);
+ } else {
+ if (modificationTyp != null) {
+ switch (modificationTyp) {
+ case SUBTREE_MODIFIED: // Create or modify sub level node
+ case WRITE: // Create or modify top level node
+ // Treat an overwrite as an update
+ // leaveconnected state.before = connected; state.after != connected
+ // enterConnected state.after == connected
+ // => Here create or update by checking root.getDataBefore() != null
+
+ boolean connectedBefore, connectedAfter;
+ NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter());
+ connectedAfter = isConnected(nNodeAfter);
+ if (root.getDataBefore() != null) {
+ // It is an update
+ NetconfNode nodeBefore = getNetconfNode(root.getDataBefore());
+ connectedBefore = isConnected(nodeBefore);
+ } else {
+ // It is a create
+ connectedBefore = false;
+ }
+
+ LOG.info(
+ "L1 NETCONF Node change with id {} ConnectedBefore {} connectedAfter {} cluster status {} akkaIsCluster",
+ nodeId, connectedBefore, connectedAfter,
+ getClusteredConnectionStatus(nNodeAfter), isCluster);
+
+ if (!connectedBefore && connectedAfter) {
+ netconfNodeStateListenerList.forEach(item -> {
+ try {
+ item.onCreated(nodeId, nNodeAfter);
+ } catch (Exception e) {
+ LOG.info("Exception during onCreated listener call", e);
+ }
+ });
+ enterConnectedState(nodeId, nNodeAfter);
+ } else {
+ LOG.debug("State change {} {}", connectedBefore, connectedAfter);
+ if (connectedBefore && !connectedAfter) {
+ leaveConnectedState(nodeId);
+ }
+ netconfNodeStateListenerList.forEach(item -> {
+ try {
+ item.onStateChange(nodeId, nNodeAfter);
+ } catch (Exception e) {
+ LOG.info("Exception during onStateChange listener call", e);
+ }
+ });
+ }
+ // doProcessing(update ? Action.UPDATE : Action.CREATE, nodeId, root);
+ break;
+ case DELETE:
+ // Node removed
+ // leaveconnected state.before = connected;
+ leaveConnectedState(nodeId);
+ netconfNodeStateListenerList.forEach(item -> {
+ try {
+ item.onRemoved(nodeId);
+ } catch (Exception e) {
+ LOG.info("Exception during onRemoved listener call", e);
+ }
+ });
+ // doProcessing(Action.REMOVE, nodeId, root);
+ break;
+ }
+ }
+ }
+ }
+ } catch (NullPointerException e) {
+ LOG.info("Data not available at ", e);
+ }
+ }
+ }
+ }
+
+ private static @Nullable NetconfNode getNetconfNode(Node node) {
+ return node != null ? node.augmentation(NetconfNode.class) : null;
+ }
+
+ private static boolean isConnected(NetconfNode nNode) {
+ return nNode != null ? ConnectionStatus.Connected.equals(nNode.getConnectionStatus()) : false;
+ }
+
+ private static @Nullable ClusteredConnectionStatus getClusteredConnectionStatus(NetconfNode node) {
+ return node != null ? node.getClusteredConnectionStatus() : null;
+ }
+ /**
+ * Normal listener function to select the right node from DataObjectModification
+ */
+ private class L2 implements DataTreeChangeListener<Node> {
+
+ @Override
+ public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
+ LOG.info("L2 TreeChange, changes:{}", changes.size());
+ }
+ }
+
+ /* -- LOG related functions -- */
+
+ /** Analyze configuration **/
+ private static @Nullable AkkaConfig getAkkaConfig() {
+ AkkaConfig akkaConfig;
+ try {
+ akkaConfig = AkkaConfig.load();
+ LOG.debug("akka.conf loaded: " + akkaConfig.toString());
+ } catch (Exception e1) {
+ akkaConfig = null;
+ LOG.warn("problem loading akka.conf: " + e1.getMessage());
+ }
+ if (akkaConfig != null && akkaConfig.isCluster()) {
+ LOG.info("cluster mode detected");
+ if (GeoConfig.fileExists()) {
+ try {
+ LOG.debug("try to load geoconfig");
+ GeoConfig.load();
+ } catch (Exception err) {
+ LOG.warn("problem loading geoconfig: " + err.getMessage());
+ }
+ } else {
+ LOG.debug("no geoconfig file found");
+ }
+ } else {
+ LOG.info("single node mode detected");
+ }
+ return akkaConfig;
+ }
+
+ private boolean isNetconfNodeMaster(NetconfNode nNode) {
+ if (this.isCluster) {
+ LOG.debug("check if me is responsible for node");
+ ClusteredConnectionStatus ccs = nNode.getClusteredConnectionStatus();
+ @SuppressWarnings("null")
+ @NonNull String masterNodeName = ccs == null || ccs.getNetconfMasterNode() == null ? "null" : ccs.getNetconfMasterNode();
+ LOG.debug("sdnMasterNode=" + masterNodeName + " and sdnMyNode=" + this.clusterName);
+ if (!masterNodeName.equals(this.clusterName)) {
+ LOG.debug("netconf change but me is not master for this node");
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ private void sleepMs(int milliseconds) {
+ try {
+ Thread.sleep(milliseconds);
+ } catch (InterruptedException e) {
+ LOG.debug("Interrupted sleep");
+ // Restore interrupted state...
+ Thread.currentThread().interrupt();
+ }
+ }
+
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java
new file mode 100644
index 0000000..d0ea0eb
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka;
+
+import java.io.File;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+
+public class AkkaConfig {
+
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(AkkaConfig.class);
+
+ private static final String DEFAULT_FILENAME = "configuration/initial/akka.conf";
+ private final String filename;
+ private ClusterConfig cluserConfig;
+
+ public ClusterConfig getClusterConfig() {
+ return this.cluserConfig;
+ }
+
+ private AkkaConfig(String filename) {
+ this.filename = filename;
+ }
+
+ public AkkaConfig() {
+ this(null);
+ }
+
+ @Override
+ public String toString() {
+ return "AkkaConfig [filename=" + filename + ", cluserConfig=" + cluserConfig + "]";
+ }
+
+ private void loadFromFile() throws Exception {
+ Config cfg = ConfigFactory.parseFile(new File(this.filename));
+ this.cluserConfig = new ClusterConfig(cfg.getConfig("odl-cluster-data").getConfig("akka").getConfig("cluster"));
+ }
+
+ public boolean isCluster() {
+ return this.cluserConfig != null ? this.cluserConfig.isCluster() : false;
+ }
+
+ public boolean isClusterAndFirstNode() {
+ return isSingleNode() || isCluster() && getClusterConfig().getRoleMemberIndex() == 1;
+ }
+
+ public static AkkaConfig load() throws Exception {
+ return load(DEFAULT_FILENAME);
+ }
+
+ public static AkkaConfig load(String filename) throws Exception {
+ AkkaConfig cfg = new AkkaConfig(filename);
+ cfg.loadFromFile();
+ return cfg;
+ }
+
+ public boolean isSingleNode() {
+ return !this.isCluster();
+ }
+ public static AkkaConfig parse(String content) throws Exception {
+ Config cfg = ConfigFactory.parseString(content);
+ AkkaConfig c = new AkkaConfig();
+ c.cluserConfig=new ClusterConfig(cfg.getConfig("odl-cluster-data").getConfig("akka").getConfig("cluster"));
+ return c;
+ }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java
new file mode 100644
index 0000000..bdde308
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.ClusterRoleInfo;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.ClusterRoleInfoCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.typesafe.config.Config;
+
+public class ClusterConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClusterConfig.class);
+
+ private final List<ClusterNodeInfo> seedNodes;
+ private final ClusterRoleInfoCollection roles;
+ private ClusterNodeInfo ismeInfo;
+
+ public static ClusterConfig defaultSingleNodeConfig()
+ {
+ ClusterConfig cfg=new ClusterConfig();
+ cfg.ismeInfo=ClusterNodeInfo.defaultSingleNodeInfo();
+ cfg.seedNodes.add(cfg.ismeInfo);
+ cfg.roles.add(ClusterRoleInfo.defaultSingleNodeRole());
+ return cfg;
+ }
+ public ClusterConfig()
+ {
+ this.seedNodes = new ArrayList<>();
+ this.roles = new ClusterRoleInfoCollection();
+
+ }
+ public ClusterConfig(Config o) throws Exception {
+ {
+ this.seedNodes = new ArrayList<>();
+ this.roles = new ClusterRoleInfoCollection();
+ List<String> a = o.getStringList("seed-nodes");
+ for (int i = 0; i < a.size(); i++) {
+ ClusterNodeInfo info = new ClusterNodeInfo(a.get(i));
+ this.seedNodes.add(info);
+ }
+ a = o.getStringList("roles");
+ for (int i = 0; i < a.size(); i++) {
+ ClusterRoleInfo s = new ClusterRoleInfo(a.get(i));
+ this.roles.add(s);
+ }
+ int idx = this.roles.get(0).getIndex() - 1;
+ if (idx >= 0 && idx < this.seedNodes.size()) {
+ this.ismeInfo = this.seedNodes.get(idx);
+ } else {
+ this.ismeInfo = null;
+ }
+ }
+
+ }
+
+ public boolean isCluster() {
+ return this.seedNodes != null ? this.seedNodes.size() > 1 : false;
+ }
+
+ public boolean isMe(ClusterNodeInfo i) {
+ return this.ismeInfo != null ? this.ismeInfo.equals(i) : false;
+ }
+
+ public List<ClusterNodeInfo> getSeedNodes() {
+ return this.seedNodes;
+ }
+
+ public String getHostName(String defaultValue) {
+ if (getRoleMemberIndex() > 0 && getRoleMemberIndex() <= seedNodes.size()) {
+ return this.seedNodes.get(getRoleMemberIndex()-1).getRemoteAddress();
+ } else {
+ LOG.warn("Seednode not available for roleMemberIndex {}. Using default {}",getRoleMember(), defaultValue);
+ return defaultValue;
+ }
+ }
+
+ public String getDBClusterName(String defaultValue) {
+ String r = null;
+ if (this.seedNodes != null && this.seedNodes.size() > 0) {
+ r = String.format("cluster-%s.%d", this.seedNodes.get(0).getRemoteAddress(), this.seedNodes.get(0).getPort());
+ }
+ if (r == null || r.isEmpty()) {
+ r = defaultValue;
+ }
+ return r;
+ }
+ public String getClusterSeedNodeName() {
+ return this.getClusterSeedNodeName("");
+ }
+ public String getClusterSeedNodeName(String defaultValue) {
+ int idx=this.getRoleMemberIndex()-1;
+ String r=null;
+ if(this.seedNodes!=null && idx>=0 && this.seedNodes.size()>0 && this.seedNodes.size()>idx)
+ {
+ r=this.seedNodes.get(idx).getSeedNodeName();
+ }
+ if (r == null || r.isEmpty()) {
+ r = defaultValue;
+ }
+ return r;
+ }
+ public int getRoleMemberIndex() {
+
+ ClusterRoleInfo role=this.roles.get("member");
+ return role!=null?role.getIndex():0;
+ }
+ public ClusterRoleInfo getRoleMember() {
+ return this.roles.get("member");
+ }
+
+ @Override
+ public String toString() {
+ return "ClusterConfig [seedNodes=" + seedNodes + ", roles=" + roles + ", ismeInfo=" + ismeInfo + "]";
+ }
+
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java
new file mode 100644
index 0000000..ef161ad
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ClusterNodeInfo {
+ private final String protocol;
+ private final String clusterName;
+ private final String remoteAdr;
+ private final int port;
+ private final String seedNodeName;
+
+ public static ClusterNodeInfo defaultSingleNodeInfo() {
+ return new ClusterNodeInfo("akka.tcp","opendaylight-cluster-data","127.0.0.1",2550);
+ }
+
+ public ClusterNodeInfo(String s) throws Exception {
+ final String regex = "([a-z.]*):\\/\\/([a-zA-Z0-9-]*)@([a-zA-Z0-9.-]*):([0-9]*)";
+ final Pattern pattern = Pattern.compile(regex);
+ final Matcher matcher = pattern.matcher(s);
+ if (!matcher.find()) {
+ throw new Exception("invalid seedNode format");
+ }
+ this.seedNodeName = matcher.group();
+ this.protocol = matcher.group(1);
+ this.clusterName = matcher.group(2);
+ this.remoteAdr = matcher.group(3);
+ this.port = Integer.parseInt(matcher.group(4));
+ }
+
+ public ClusterNodeInfo(String protocol, String clustername, String remoteadr, int port) {
+ this.protocol=protocol;
+ this.clusterName=clustername;
+ this.remoteAdr=remoteadr;
+ this.port=port;
+ this.seedNodeName=this.protocol+"://"+this.clusterName+"@"+this.remoteAdr+":"+this.port;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public String getRemoteAddress() {
+ return remoteAdr;
+ }
+ public String getSeedNodeName() {
+ return seedNodeName;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ public String toString() {
+ return "ClusterNodeInfo [protocol=" + protocol + ", clusterName=" + clusterName + ", remoteAdr=" + remoteAdr
+ + ", port=" + port + ", seedNodeName=" + seedNodeName + "]";
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java
new file mode 100644
index 0000000..994ef54
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ClusterRoleInfo {
+ private final String Role;
+ private final int Index;
+
+ public ClusterRoleInfo(String s) throws Exception {
+ final String regex = "([a-zA-Z]*)-([0-9]*)";
+ final Pattern pattern = Pattern.compile(regex);
+ final Matcher matcher = pattern.matcher(s);
+ if (!matcher.find()) {
+ throw new Exception("unexpected role format:"+s);
+ }
+ this.Role = matcher.group(1);
+ this.Index = Integer.parseInt(matcher.group(2));
+ }
+
+ private ClusterRoleInfo(String role, int idx) {
+ this.Role=role;
+ this.Index=idx;
+ }
+
+ public static ClusterRoleInfo defaultSingleNodeRole() {
+ return new ClusterRoleInfo("member",1);
+ }
+
+ public String getRole() {
+ return Role;
+ }
+ public int getIndex() {
+ return Index;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Index;
+ result = prime * result + (Role == null ? 0 : Role.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ClusterRoleInfo other = (ClusterRoleInfo) obj;
+ if (Index != other.Index) {
+ return false;
+ }
+ if (Role == null) {
+ if (other.Role != null) {
+ return false;
+ }
+ } else if (!Role.equals(other.Role)) {
+ return false;
+ }
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "ClusterRoleInfo [Role=" + Role + ", Index=" + Index + "]";
+ }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java
new file mode 100644
index 0000000..478ed83
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo;
+
+import java.util.ArrayList;
+
+public class ClusterRoleInfoCollection extends ArrayList<ClusterRoleInfo> {
+ private static final long serialVersionUID = 1L;
+
+ public ClusterRoleInfo get(String role) {
+ for (ClusterRoleInfo info : this) {
+ if (info.getRole().equals(role)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ public boolean contains(ClusterRoleInfo info) {
+ if (info == null) {
+ return false;
+ }
+ for (ClusterRoleInfo i : this) {
+ if (i.equals(info)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java
new file mode 100644
index 0000000..c25f326
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+
+public class GeoConfig {
+
+ private static final String DEFAULT_FILENAME = "configuration/initial/geo.conf";
+ private static final String LUMINA_ROOTNODENAME = "lumina-geo-cluster";
+ private final String filename;
+ private final String rootNodename;
+ private ClusterRoleInfoCollection primaryRoles;
+ private ClusterRoleInfoCollection secondayRoles;
+ private RolesTable rolesTable;
+
+ private GeoConfig() {
+ this(null);
+ }
+
+ private GeoConfig(String filename) {
+ this(filename, LUMINA_ROOTNODENAME);
+ }
+
+ private GeoConfig(String filename, String rootNodeName) {
+ this.filename = filename;
+ this.rootNodename = rootNodeName;
+ }
+
+ public static boolean fileExists() {
+ File f = new File(DEFAULT_FILENAME);
+ return f.exists();
+ }
+
+ public static GeoConfig load() throws Exception {
+ return load(DEFAULT_FILENAME);
+ }
+
+ public static GeoConfig load(String filename) throws Exception {
+ GeoConfig cfg = new GeoConfig(filename);
+ cfg._load();
+ return cfg;
+ }
+
+ private void _load() throws Exception {
+ this._load(ConfigFactory.parseFile(new File(this.filename)));
+ }
+
+ private void _load(Config cfg) throws Exception {
+ this.primaryRoles = new ClusterRoleInfoCollection();
+ List<String> a = cfg.getConfig(this.rootNodename).getStringList("primary_roles");
+
+ for (int i = 0; i < a.size(); i++) {
+ ClusterRoleInfo s = new ClusterRoleInfo(a.get(i));
+ this.primaryRoles.add(s);
+ }
+ this.secondayRoles = new ClusterRoleInfoCollection();
+ a = cfg.getConfig(this.rootNodename).getStringList("secondary_roles");
+ for (int i = 0; i < a.size(); i++) {
+ ClusterRoleInfo s = new ClusterRoleInfo(a.get(i));
+ this.secondayRoles.add(s);
+ }
+ this.checkDuplicateRoleEntries();
+ this.rolesTable = new RolesTable(cfg.getConfig(this.rootNodename).getConfigList("ip_roles_table"));
+ }
+
+ private void checkDuplicateRoleEntries() throws Exception {
+ ClusterRoleInfoCollection duplicateEntries = new ClusterRoleInfoCollection();
+ for (ClusterRoleInfo primaryRole : this.primaryRoles) {
+ if (this.secondayRoles.contains(primaryRole)) {
+ duplicateEntries.add(primaryRole);
+ }
+ }
+ if (duplicateEntries.size() > 0) {
+ throw new Exception("duplicate entries found: " + duplicateEntries.toString());
+ }
+
+ }
+
+ public static GeoConfig parse(String content) throws Exception {
+ GeoConfig cfg = new GeoConfig();
+ cfg._load(ConfigFactory.parseString(content));
+ return cfg;
+ }
+
+ public ClusterRoleInfoCollection getPrimaryRoles() {
+ return this.primaryRoles;
+ }
+
+ public ClusterRoleInfoCollection getSecondaryRoles() {
+ return this.secondayRoles;
+ }
+
+ public boolean isPrimary(ClusterRoleInfo roleMember) {
+ return !this.isSecondary(roleMember);
+ }
+
+ private boolean isSecondary(ClusterRoleInfo roleMember) {
+ if (roleMember == null) {
+ return false;
+ }
+ for (ClusterRoleInfo info : this.secondayRoles) {
+ if (info.equals(roleMember)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "GeoConfig [filename=" + filename + ", rootNodename=" + rootNodename + ", primaryRoles=" + primaryRoles
+ + ", secondayRoles=" + secondayRoles + ", rolesTable=" + rolesTable + "]";
+ }
+
+ public static class RolesTableEntry {
+ private final ClusterRoleInfo role;
+ private final String ip;
+
+ public RolesTableEntry(Config c) throws Exception {
+ this.role = new ClusterRoleInfo(c.getString("role"));
+ this.ip = c.getString("ip");
+ }
+
+ @Override
+ public String toString() {
+ return "RolesTableEntry [role=" + role + ", ip=" + ip + "]";
+ }
+ }
+ public static class RolesTable extends ArrayList<RolesTableEntry> {
+ private static final long serialVersionUID = -9146218864237487506L;
+
+ public RolesTable(List<? extends Config> configList) throws Exception {
+ for (Config c : configList) {
+ this.add(new RolesTableEntry(c));
+ }
+ }
+
+ }
+
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java
new file mode 100644
index 0000000..9215887
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc;
+
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.AttributeChangeNotificationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.FaultNotificationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.NetconfnodeStateService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushAttributeChangeNotificationInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushAttributeChangeNotificationOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushFaultNotificationInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushFaultNotificationOutput;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+
+public class NetconfnodeStateServiceRpcApiImpl implements NetconfnodeStateService, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfnodeStateServiceRpcApiImpl.class);
+
+ private final ObjectRegistration<NetconfnodeStateServiceRpcApiImpl> rpcReg;
+ private RpcApigetStateCallback getStatusCallback;
+ private final List<VesNotificationListener> vesNotificationListenerList;
+
+ public NetconfnodeStateServiceRpcApiImpl(final RpcProviderService rpcProviderRegistry,
+ List<VesNotificationListener> vesNotificationListenerList) {
+
+ this.vesNotificationListenerList = vesNotificationListenerList;
+
+ // Register ourselves as the REST API RPC implementation
+ LOG.info("Register RPC Service " + NetconfnodeStateService.class.getSimpleName());
+ rpcReg = rpcProviderRegistry.registerRpcImplementation(NetconfnodeStateService.class, this);
+ this.getStatusCallback = null;
+ }
+
+ public NetconfnodeStateServiceRpcApiImpl setStatusCallback(RpcApigetStateCallback getStatusCallback) {
+ this.getStatusCallback = getStatusCallback;
+ return this;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.info("Close RPC Service");
+ if (rpcReg != null) {
+ rpcReg.close();
+ }
+ }
+
+ /*-------------------------------
+ * Interfaces for getting information
+ */
+ @Override
+ public ListenableFuture<RpcResult<GetStatusOutput>> getStatus(GetStatusInput input) {
+
+ LOG.info("RPC Request: getStatus input: {}", input);
+ RpcResultBuilder<GetStatusOutput> result;
+
+ try {
+ GetStatusOutputBuilder outputBuilder = new GetStatusOutputBuilder();
+ getStatusCallback.getStatus(input);
+ result = RpcResultBuilder.success(outputBuilder);
+ } catch (Exception e) {
+ result = RpcResultBuilder.failed();
+ result.withError(ErrorType.APPLICATION, "Exception", e);
+ }
+ return result.buildFuture();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<PushFaultNotificationOutput>> pushFaultNotification(
+ PushFaultNotificationInput input) {
+
+ RpcResultBuilder<PushFaultNotificationOutput> result;
+ try {
+ FaultNotificationBuilder faultNotificationBuilder = new FaultNotificationBuilder();
+ faultNotificationBuilder.fieldsFrom(input);
+ vesNotificationListenerList.forEach(item -> item.onNotification(faultNotificationBuilder.build()));
+ result = RpcResultBuilder.success();
+ } catch (Exception e) {
+ result = RpcResultBuilder.failed();
+ result.withError(ErrorType.APPLICATION, "Exception", e);
+ }
+ return result.buildFuture();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<PushAttributeChangeNotificationOutput>> pushAttributeChangeNotification(
+ PushAttributeChangeNotificationInput input) {
+ RpcResultBuilder<PushAttributeChangeNotificationOutput> result;
+ try {
+ AttributeChangeNotificationBuilder attributeChangeNotificationBuilder = new AttributeChangeNotificationBuilder();
+ attributeChangeNotificationBuilder.fieldsFrom(input);
+ vesNotificationListenerList.forEach(item -> item.onNotification(attributeChangeNotificationBuilder.build()));
+ result = RpcResultBuilder.success();
+ } catch (Exception e) {
+ result = RpcResultBuilder.failed();
+ result.withError(ErrorType.APPLICATION, "Exception", e);
+ }
+ return result.buildFuture();
+ }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java
new file mode 100644
index 0000000..1434cf4
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder;
+
+public interface RpcApigetStateCallback {
+
+ GetStatusOutputBuilder getStatus(GetStatusInput input);
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml
new file mode 100644
index 0000000..46930ac
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+============LICENSE_START=======================================================
+ONAP : ccsdk feature sdnr wt netconfnode-service-provider
+ ================================================================================
+Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+All rights reserved.
+================================================================================
+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.
+============LICENSE_END=========================================================
+ -->
+
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" odl:use-default-for-reference-types="true">
+
+ <reference id="dataBroker" interface="org.opendaylight.mdsal.binding.api.DataBroker"
+ odl:type="default" />
+
+ <reference id="notificationPublishService"
+ interface="org.opendaylight.mdsal.binding.api.NotificationPublishService"
+ odl:type="default" />
+
+ <reference id="mountPointService"
+ interface="org.opendaylight.mdsal.binding.api.MountPointService"
+ odl:type="default" />
+
+ <reference id="rpcProviderRegistry"
+ interface="org.opendaylight.mdsal.binding.api.RpcProviderService"
+ odl:type="default" />
+
+ <reference id="clusterSingletonService"
+ interface="org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider"/>
+
+ <bean id="netconfNodeStateService" class="org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.NetconfNodeStateServiceImpl" init-method="init" destroy-method="destroy" scope="singleton">
+ <property name="dataBroker" ref="dataBroker"/>
+ <property name="rpcProviderRegistry" ref="rpcProviderRegistry" />
+ <property name="notificationPublishService" ref="notificationPublishService" />
+ <property name="mountPointService" ref="mountPointService" />
+ <property name="clusterSingletonService" ref="clusterSingletonService" />
+ </bean>
+
+ <service id="registerNetconfNodeStateService"
+ interface="org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateService"
+ ref="netconfNodeStateService" />
+
+</blueprint>
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties
new file mode 100644
index 0000000..8037339
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties
@@ -0,0 +1,3 @@
+# Proberties filled in by maven during build process
+version = ${project.version}
+build = ${buildtime}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestAkkaConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestAkkaConfig.java
new file mode 100644
index 0000000..dd317c7
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestAkkaConfig.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.AkkaConfig;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.ClusterConfig;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.ClusterNodeInfo;
+
+public class TestAkkaConfig {
+
+ private static String getAkkaConfigSingleNodeText() {
+ return "\n" + "odl-cluster-data {\n" + " akka {\n" + " remote {\n" + " artery {\n"
+ + " enabled = off\n" + " canonical.hostname = \"127.0.0.1\"\n"
+ + " canonical.port = 2550\n" + " }\n" + " netty.tcp {\n"
+ + " hostname = \"127.0.0.1\"\n" + " port = 2550\n" + " }\n"
+ + " # when under load we might trip a false positive on the failure detector\n"
+ + " # transport-failure-detector {\n" + " # heartbeat-interval = 4 s\n"
+ + " # acceptable-heartbeat-pause = 16s\n" + " # }\n" + " }\n" + "\n" + " cluster {\n"
+ + " # Remove \".tcp\" when using artery.\n"
+ + " seed-nodes = [\"akka.tcp://opendaylight-cluster-data@127.0.0.1:2550\"]\n" + "\n"
+ + " roles = [\n" + " \"member-1\"\n" + " ]\n" + "\n" + " }\n" + "\n"
+ + " persistence {\n"
+ + " # By default the snapshots/journal directories live in KARAF_HOME. You can choose to put it somewhere else by\n"
+ + " # modifying the following two properties. The directory location specified may be a relative or absolute path. \n"
+ + " # The relative path is always relative to KARAF_HOME.\n" + "\n"
+ + " # snapshot-store.local.dir = \"target/snapshots\"\n"
+ + " # journal.leveldb.dir = \"target/journal\"\n" + "\n" + " journal {\n"
+ + " leveldb {\n" + " # Set native = off to use a Java-only implementation of leveldb.\n"
+ + " # Note that the Java-only version is not currently considered by Akka to be production quality.\n"
+ + "\n" + " # native = off\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}";
+ }
+
+ private static String getAkkaConfigClusterNodeText() {
+ return "\n" + "odl-cluster-data {\n" + "\n" + " akka {\n" + " loglevel = \"\"\n" + " remote {\n"
+ + " netty.tcp {\n" + " hostname = \"zltcmtn23arbc01.2f0377.mtn23a.tci.att.com\"\n"
+ + " port = 2550\n" + " }\n" + " }\n" + " actor {\n" + " debug{\n"
+ + " autoreceive = on\n" + " lifecycle = on\n" + " unhandled = on\n"
+ + " fsm = on\n" + " event-stream = on\n" + " }\n" + " }\n" + " cluster {\n"
+ + " seed-nodes = [\"akka.tcp://opendaylight-cluster-data@zltcmtn23arbc01.2f0377.mtn23a.tci.att.com:2550\", \"akka.tcp://opendaylight-cluster-data@zltcmtn23arbc02.2f0377.mtn23a.tci.att.com:2550\", \"akka.tcp://opendaylight-cluster-data@zltcmtn23arbc03.2f0377.mtn23a.tci.att.com:2550\", \"akka.tcp://opendaylight-cluster-data@zltcmtn23brbc01.f84e7a.mtn23b.tci.att.com:2550\", \"akka.tcp://opendaylight-cluster-data@zltcmtn23brbc02.f84e7a.mtn23b.tci.att.com:2550\", \"akka.tcp://opendaylight-cluster-data@zltcmtn23brbc03.f84e7a.mtn23b.tci.att.com:2550\"]\n"
+ + " seed-node-timeout = 15s\n" + " roles = [\"member-1\"]\n" + "\n" + " }\n"
+ + " persistence {\n" + " journal-plugin-fallback {\n" + " circuit-breaker {\n"
+ + " max-failures = 10\n" + " call-timeout = 60s\n"
+ + " reset-timeout = 30s\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}\n" + "\n"
+ + "odl-cluster-rpc {\n" + "\n" + " akka {\n" + " loglevel = \"\"\n" + " remote {\n"
+ + " netty.tcp {\n" + " hostname = \"zltcmtn23arbc01.2f0377.mtn23a.tci.att.com\"\n"
+ + " port = 2551\n" + " }\n" + " }\n" + " actor {\n" + " debug{\n"
+ + " autoreceive = on\n" + " lifecycle = on\n" + " unhandled = on\n"
+ + " fsm = on\n" + " event-stream = on\n" + " }\n" + " }\n" + " cluster {\n"
+ + " seed-nodes = [\"akka.tcp://odl-cluster-rpc@zltcmtn23arbc01.2f0377.mtn23a.tci.att.com:2551\", \"akka.tcp://odl-cluster-rpc@zltcmtn23arbc02.2f0377.mtn23a.tci.att.com:2551\", \"akka.tcp://odl-cluster-rpc@zltcmtn23arbc03.2f0377.mtn23a.tci.att.com:2551\", \"akka.tcp://odl-cluster-rpc@zltcmtn23brbc01.f84e7a.mtn23b.tci.att.com:2551\", \"akka.tcp://odl-cluster-rpc@zltcmtn23brbc02.f84e7a.mtn23b.tci.att.com:2551\", \"akka.tcp://odl-cluster-rpc@zltcmtn23brbc03.f84e7a.mtn23b.tci.att.com:2551\"]\n"
+ + " seed-node-timeout = 15s\n" + " }\n" + " persistence {\n"
+ + " journal-plugin-fallback {\n" + " circuit-breaker {\n" + " max-failures = 10\n"
+ + " call-timeout = 60s\n" + " reset-timeout = 30s\n" + " }\n" + " }\n"
+ + " }\n" + " }\n" + "}\n" + "\n" + "";
+ }
+
+ @Test
+ public void test1() {
+ AkkaConfig cfg;
+ try {
+ System.out.println("testing clusternode config1");
+ System.out.println("===========================");
+ cfg = AkkaConfig.parse(getAkkaConfigClusterNodeText());
+ System.out.println("succeeded: ");
+ System.out.println(cfg.toString());
+ System.out.println(String.format("found %d cluster nodes", cfg.getClusterConfig().getSeedNodes().size()));
+ for (ClusterNodeInfo n : cfg.getClusterConfig().getSeedNodes()) {
+ System.out.println(n.toString());
+ }
+ } catch (Exception e) {
+ String failMessage = "failed: " + e.getMessage();
+ System.out.println(failMessage);
+ fail(failMessage);
+ }
+ }
+
+ @Test
+ public void test2() {
+ AkkaConfig cfg;
+ try {
+ System.out.println("testing singlenode config1");
+ System.out.println("===========================");
+ cfg = AkkaConfig.parse(getAkkaConfigSingleNodeText());
+ System.out.println("succeeded: ");
+ System.out.println(cfg.toString());
+ } catch (Exception e) {
+ String failMessage = "failed: " + e.getMessage();
+ System.out.println(failMessage);
+ fail(failMessage);
+ }
+ }
+
+ @Test
+ public void test3() {
+ AkkaConfig cfg;
+
+ ClassLoader classLoader = getClass().getClassLoader();
+ File file = new File(classLoader.getResource("captured-akka.conf").getFile());
+ System.out.println(file.getAbsolutePath());
+
+ try {
+ System.out.println("testing clusternode config1");
+ System.out.println("===========================");
+ cfg = AkkaConfig.load(file.getAbsolutePath());
+ System.out.println("succeeded: "+cfg.hashCode());
+ System.out.println(cfg.toString());
+ System.out.println(String.format("found %d cluster nodes", cfg.getClusterConfig().getSeedNodes().size()));
+ for (ClusterNodeInfo n : cfg.getClusterConfig().getSeedNodes()) {
+ System.out.println(n.toString());
+ }
+ } catch (Exception e) {
+ String failMessage = "failed: " + e.getMessage();
+ System.out.println(failMessage);
+ fail(failMessage);
+ }
+ }
+
+ @Test
+ public void test4() {
+ ClusterConfig cc = ClusterConfig.defaultSingleNodeConfig();
+ cc.getClusterSeedNodeName();
+ cc.getRoleMemberIndex();
+ cc.isCluster();
+ cc.isMe(null);
+ }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestGeoConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestGeoConfig.java
new file mode 100644
index 0000000..915c88d
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestGeoConfig.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.GeoConfig;
+
+public class TestGeoConfig {
+
+ @Test
+ public void test() {
+ GeoConfig config;
+ try {
+ System.out.println("testing clusternode geo config1");
+ System.out.println("===========================");
+ config = GeoConfig.parse(getClusterGeoConfigContent());
+ System.out.println("succeeded: ");
+ System.out.println(config.toString());
+ System.out.println("primary roles:");
+ System.out.println(config.getPrimaryRoles().toString());
+ System.out.println("secondary roles:");
+ System.out.println(config.getSecondaryRoles().toString());
+
+ } catch (Exception e) {
+ fail("failed: " + e.getMessage());
+ }
+ }
+
+
+
+ private static String getClusterGeoConfigContent() {
+ return "\n" + "lumina-geo-cluster {\n" + " primary_roles = [\n"
+ + " \"member-1\",\"member-2\",\"member-3\"\n" + " ]\n" + " secondary_roles = [\n"
+ + " \"member-4\",\"member-5\",\"member-6\"\n" + " ]\n" + " ip_roles_table = [\n" + "\n"
+ + " {\n" + "role=\"member-1\"\n" + "ip=\"zltcmtn23arbc01.2f0377.mtn23a.tci.att.com\"\n" + "},\n"
+ + "{\n" + "role=\"member-2\"\n" + "ip=\"zltcmtn23arbc02.2f0377.mtn23a.tci.att.com\"\n" + "},\n" + "{\n"
+ + "role=\"member-3\"\n" + "ip=\"zltcmtn23arbc03.2f0377.mtn23a.tci.att.com\"\n" + "},\n" + "{\n"
+ + "role=\"member-4\"\n" + "ip=\"zltcmtn23brbc01.f84e7a.mtn23b.tci.att.com\"\n" + "},\n" + "{\n"
+ + "role=\"member-5\"\n" + "ip=\"zltcmtn23brbc02.f84e7a.mtn23b.tci.att.com\"\n" + "},\n" + "{\n"
+ + "role=\"member-6\"\n" + "ip=\"zltcmtn23brbc03.f84e7a.mtn23b.tci.att.com\"\n" + "}\n" + " \n"
+ + " ]\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "";
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java
new file mode 100644
index 0000000..ff659ca
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * ============LICENSE_START======================================================= ONAP : ccsdk
+ * feature sdnr wt ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * ================================================================================ 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. ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnectListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.NetconfNodeStateServiceImpl;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.NetconfnodeStateServiceRpcApiImpl;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.ClusterSingletonServiceProviderMock;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.DataBrokerNetconfMock;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.MountPointMock;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.MountPointServiceMock;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.NotificationPublishServiceMock;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.RpcProviderRegistryMock;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.binding.api.MountPointService;
+import org.opendaylight.mdsal.binding.api.NotificationPublishService;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.AttributeChangeNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.AttributeChangeNotificationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.FaultNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.FaultNotificationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushAttributeChangeNotificationInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushAttributeChangeNotificationOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushFaultNotificationInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushFaultNotificationOutput;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class TestNetconfNodeStateService {
+
+ private static Path KARAF_ETC = Paths.get("etc");
+ private static NetconfNodeStateServiceImpl netconfStateService;
+ private static MountPointMock mountPoint;
+ private static DataBrokerNetconfMock dataBrokerNetconf;
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestNetconfNodeStateService.class);
+
+ @BeforeClass
+ public static void before() throws InterruptedException, IOException {
+
+ System.out.println("Logger: " + LOG.getClass().getName() + " " + LOG.getName());
+ // Call System property to get the classpath value
+ Path etc = KARAF_ETC;
+ delete(etc);
+
+ System.out.println("Create empty:" + etc.toString());
+ Files.createDirectories(etc);
+
+ // Create mocks
+ dataBrokerNetconf = new DataBrokerNetconfMock();
+ dataBrokerNetconf.newReadWriteTransaction();
+ mountPoint = new MountPointMock();
+ ClusterSingletonServiceProvider clusterSingletonService = new ClusterSingletonServiceProviderMock();
+ MountPointService mountPointService = new MountPointServiceMock(mountPoint);
+ NotificationPublishService notificationPublishService = new NotificationPublishServiceMock();
+ RpcProviderService rpcProviderRegistry = new RpcProviderRegistryMock();
+
+ // start using blueprint interface
+ netconfStateService = new NetconfNodeStateServiceImpl();
+
+ netconfStateService.setDataBroker(dataBrokerNetconf);
+ netconfStateService.setMountPointService(mountPointService);
+ netconfStateService.setNotificationPublishService(notificationPublishService);
+ netconfStateService.setRpcProviderRegistry(rpcProviderRegistry);
+ netconfStateService.setClusterSingletonService(clusterSingletonService);
+ netconfStateService.init();
+ System.out.println("Initialization done");
+ }
+
+ @AfterClass
+ public static void after() throws InterruptedException, IOException {
+ System.out.println("Start shutdown");
+ // close using blueprint interface
+ netconfStateService.close();
+ delete(KARAF_ETC);
+
+ }
+
+ @Test
+ public void test1() {
+
+ System.out.println("Test1: Verify init state");
+ assertTrue("Devicemanager not initialized", netconfStateService.isInitializationSuccessful());
+ }
+
+
+ @Test
+ public void test2() {
+
+ System.out.println("Test2: Register state listener");
+
+ NetconfNodeStateListener nSL = mock(NetconfNodeStateListener.class);
+ ListenerRegistration<NetconfNodeStateListener> res =
+ netconfStateService.registerNetconfNodeStateListener(nSL);
+ assertNotNull("Result should be null", res);
+ res.getInstance();
+ res.close();
+ }
+
+ @Test
+ public void test3() {
+
+ System.out.println("Test3: Register connect listener");
+
+ NetconfNodeConnectListener nCL = mock(NetconfNodeConnectListener.class);
+ ListenerRegistration<NetconfNodeConnectListener> res =
+ netconfStateService.registerNetconfNodeConnectListener(nCL);
+ assertNotNull("Result should be null", res);
+ res.getInstance();
+ res.close();
+ }
+
+ @Test
+ public void test4() {
+ System.out.println("Test4: Get status listener");
+ GetStatusInputBuilder inputBuilder = new GetStatusInputBuilder();
+ GetStatusOutputBuilder res = netconfStateService.getStatus(inputBuilder.build());
+ assertNotNull("Result should be null", res);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test5OnConnect() {
+ System.out.println("Test5: On Connect");
+ NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
+ netconfNodeBuilder.setConnectionStatus(ConnectionStatus.Connected);
+ NetconfNode rootNodeNetconf = netconfNodeBuilder.build();
+
+ NodeId nodeId = new NodeId("Test");
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.addAugmentation(NetconfNode.class, rootNodeNetconf);
+ nodeBuilder.setNodeId(nodeId);
+ Node rootNode = nodeBuilder.build();
+
+ DataObjectModification<Node> dom = mock(DataObjectModification.class);
+ when(dom.getDataAfter()).thenReturn(rootNode);
+ when(dom.getModificationType()).thenReturn(ModificationType.WRITE);
+
+ DataTreeModification<Node> ntn = mock(DataTreeModification.class);
+ when(ntn.getRootNode()).thenReturn(dom);
+
+ NetconfNodeConnectListener nCL = mock(NetconfNodeConnectListener.class);
+ netconfStateService.registerNetconfNodeConnectListener(nCL);
+ mountPoint.setDatabrokerAbsent(false);
+
+ Collection<DataTreeModification<Node>> changes = Arrays.asList(ntn);
+ dataBrokerNetconf.sendClusteredChanges(changes);
+ dataBrokerNetconf.sendChanges(changes);
+
+ //verify that it was called one time
+ verify(nCL,times(1)).onEnterConnected(nodeId, rootNodeNetconf, mountPoint.getDataBroker());
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test6Update() {
+ System.out.println("Test6: OnChange");
+ NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
+ netconfNodeBuilder.setConnectionStatus(ConnectionStatus.Connected);
+ NetconfNode rootNodeNetconf = netconfNodeBuilder.build();
+
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.addAugmentation(NetconfNode.class, rootNodeNetconf);
+ nodeBuilder.setNodeId(new NodeId("Test"));
+ Node rootNodeAfter = nodeBuilder.build();
+
+ DataObjectModification<Node> dom = mock(DataObjectModification.class);
+ when(dom.getDataBefore()).thenReturn(rootNodeAfter);
+ when(dom.getDataAfter()).thenReturn(rootNodeAfter);
+ when(dom.getModificationType()).thenReturn(ModificationType.WRITE);
+
+ DataTreeModification<Node> ntn = mock(DataTreeModification.class);
+ when(ntn.getRootNode()).thenReturn(dom);
+
+ Collection<DataTreeModification<Node>> changes = Arrays.asList(ntn);
+ dataBrokerNetconf.sendClusteredChanges(changes);
+ dataBrokerNetconf.sendChanges(changes);
+ }
+
+ @Test
+ public void test7ApiStatus() throws InterruptedException, ExecutionException {
+
+ NetconfnodeStateServiceRpcApiImpl api = netconfStateService.getNetconfnodeStateServiceRpcApiImpl();
+
+ GetStatusInputBuilder statusInput = new GetStatusInputBuilder();
+ ListenableFuture<RpcResult<GetStatusOutput>> statusOutput = api.getStatus(statusInput.build());
+ RpcResult<GetStatusOutput> res = statusOutput.get();
+ GetStatusOutput output = res.getResult();
+ System.out.println("Output "+output);
+ }
+
+
+ @Test
+ public void test8ApiPushFault() throws InterruptedException, ExecutionException {
+
+ NetconfnodeStateServiceRpcApiImpl api = netconfStateService.getNetconfnodeStateServiceRpcApiImpl();
+
+ VesNotificationListener vNL = mock(VesNotificationListener.class);
+ ListenerRegistration<VesNotificationListener> registration = netconfStateService.registerVesNotifications(vNL);
+
+ FaultNotificationBuilder faultBuilder = new FaultNotificationBuilder();
+ faultBuilder.setProblem("problem1");
+ FaultNotification fault = faultBuilder.build();
+ PushFaultNotificationInputBuilder statusInput = new PushFaultNotificationInputBuilder();
+ statusInput.fieldsFrom(fault);
+ ListenableFuture<RpcResult<PushFaultNotificationOutput>> rpcOutput = api.pushFaultNotification(statusInput.build());
+ RpcResult<PushFaultNotificationOutput> res = rpcOutput.get();
+ PushFaultNotificationOutput output = res.getResult();
+
+ //verify that it was called one time
+ verify(vNL,times(1)).onNotification(fault);
+
+ registration.close();
+ System.out.println("Output "+output);
+ }
+
+ @Test
+ public void test9ApiPushNotifiction() throws InterruptedException, ExecutionException {
+
+ NetconfnodeStateServiceRpcApiImpl api = netconfStateService.getNetconfnodeStateServiceRpcApiImpl();
+
+ VesNotificationListener vNL = mock(VesNotificationListener.class);
+ ListenerRegistration<VesNotificationListener> registration = netconfStateService.registerVesNotifications(vNL);
+
+ AttributeChangeNotificationBuilder changeBuilder = new AttributeChangeNotificationBuilder();
+ changeBuilder.setAttributeName("attribute1");
+ AttributeChangeNotification change = changeBuilder.build();
+ PushAttributeChangeNotificationInputBuilder statusInput = new PushAttributeChangeNotificationInputBuilder();
+ statusInput.fieldsFrom(change);
+ ListenableFuture<RpcResult<PushAttributeChangeNotificationOutput>> rpcOutput = api.pushAttributeChangeNotification(statusInput.build());
+ RpcResult<PushAttributeChangeNotificationOutput> res = rpcOutput.get();
+ PushAttributeChangeNotificationOutput output = res.getResult();
+
+ //verify that it was called one time
+ verify(vNL,times(1)).onNotification(change);
+
+ registration.close();
+ System.out.println("Output "+output);
+ }
+
+
+ // ------- private section
+
+ private static void delete(Path etc) throws IOException {
+ if (Files.exists(etc)) {
+ System.out.println("Found and remove:" + etc.toString());
+ delete(etc.toFile());
+ }
+ }
+
+ private static void delete(File f) throws IOException {
+ if (f.isDirectory()) {
+ for (File c : f.listFiles()) {
+ delete(c);
+ }
+ }
+ if (!f.delete()) {
+ throw new FileNotFoundException("Failed to delete file: " + f);
+ }
+ }
+
+
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/ClusterSingletonServiceProviderMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/ClusterSingletonServiceProviderMock.java
new file mode 100644
index 0000000..86340c0
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/ClusterSingletonServiceProviderMock.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+
+public class ClusterSingletonServiceProviderMock implements ClusterSingletonServiceProvider {
+
+ @Override
+ public void close() throws Exception {
+
+ }
+
+ @Override
+ public ClusterSingletonServiceRegistration registerClusterSingletonService(ClusterSingletonService service) {
+ return null;
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/DataBrokerMountpointMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/DataBrokerMountpointMock.java
new file mode 100644
index 0000000..48401c8
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/DataBrokerMountpointMock.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.api.BindingService;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
+import org.opendaylight.mdsal.binding.api.TransactionChain;
+import org.opendaylight.mdsal.binding.api.TransactionChainListener;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+public class DataBrokerMountpointMock implements DataBroker, BindingService {
+
+ ReadTransaction readTransaction;
+
+ public void setReadOnlyTransaction(ReadTransaction readTransaction) {
+ this.readTransaction = readTransaction;
+ }
+
+ @Override
+ public @NonNull ReadTransaction newReadOnlyTransaction() {
+ return null;
+ }
+
+ @Override
+ public @NonNull ReadWriteTransaction newReadWriteTransaction() {
+ return null;
+ }
+
+ @Override
+ public @NonNull WriteTransaction newWriteOnlyTransaction() {
+ return null;
+ }
+
+ @Override
+ public <T extends DataObject, L extends DataTreeChangeListener<T>> @NonNull ListenerRegistration<L> registerDataTreeChangeListener(
+ @NonNull DataTreeIdentifier<T> treeId, @NonNull L listener) {
+ return null;
+ }
+
+ @Override
+ public @NonNull TransactionChain createTransactionChain(@NonNull TransactionChainListener listener) {
+ return null;
+ }
+
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/DataBrokerNetconfMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/DataBrokerNetconfMock.java
new file mode 100644
index 0000000..90ab860
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/DataBrokerNetconfMock.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import java.util.Collection;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+import org.opendaylight.mdsal.binding.api.TransactionChain;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+public class DataBrokerNetconfMock implements DataBroker {
+
+ private @NonNull DataTreeChangeListener<Node> listener;
+ private @NonNull ClusteredDataTreeChangeListener<Node> listenerClustered;
+
+ @Override
+ public @NonNull ReadTransaction newReadOnlyTransaction() {
+ return null;
+ }
+
+ @Override
+ public org.opendaylight.mdsal.binding.api.@NonNull ReadWriteTransaction newReadWriteTransaction() {
+ return null;
+ }
+
+ @Override
+ public org.opendaylight.mdsal.binding.api.@NonNull WriteTransaction newWriteOnlyTransaction() {
+ return null;
+ }
+
+
+ @Override
+ public @NonNull TransactionChain createTransactionChain(
+ org.opendaylight.mdsal.binding.api.@NonNull TransactionChainListener listener) {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T extends DataObject, L extends DataTreeChangeListener<T>> @NonNull ListenerRegistration<L> registerDataTreeChangeListener(
+ @NonNull DataTreeIdentifier<T> treeId, @NonNull L pListener) {
+ System.out.println("Register "+pListener.getClass().getName());
+ if (pListener instanceof ClusteredDataTreeChangeListener) {
+ System.out.println("Clustered listener");
+ this.listenerClustered = (ClusteredDataTreeChangeListener<Node>) pListener;
+ } else if (pListener instanceof DataTreeChangeListener) {
+ System.out.println("Listener");
+ this.listener = (DataTreeChangeListener<Node>) pListener;
+ }
+ return new ListenerRegistration<L>() {
+
+ @Override
+ public @NonNull L getInstance() {
+ return pListener;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ };
+ }
+
+ public void sendChanges(Collection<DataTreeModification<Node>> changes) {
+ this.listener.onDataTreeChanged(changes);
+ }
+
+ public void sendClusteredChanges(Collection<DataTreeModification<Node>> changes) {
+ this.listenerClustered.onDataTreeChanged(changes);
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/MountPointMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/MountPointMock.java
new file mode 100644
index 0000000..e5bff45
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/MountPointMock.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt sdnr-wt-devicemanager-provider
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import java.util.Optional;
+import org.opendaylight.mdsal.binding.api.BindingService;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.MountPoint;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * @author herbert
+ *
+ */
+public class MountPointMock implements MountPoint {
+
+ private boolean databrokerAbsent = true;
+ private final DataBrokerMountpointMock dataBroker = new DataBrokerMountpointMock();
+ private final RpcConsumerRegistryMock rpcConsumerRegistry = new RpcConsumerRegistryMock();
+ private NotificationService setReadTransaction;
+
+ private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID =
+ InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
+ new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
+
+ @Override
+ public InstanceIdentifier<?> getIdentifier() {
+ return NETCONF_TOPO_IID;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T extends BindingService> Optional<T> getService(Class<T> service) {
+
+ System.out.println("Requested mountpoint service: "+service.getSimpleName()+" databrokerAbsent state: "+databrokerAbsent);
+
+ Optional<? extends BindingService> res;
+ if (service.isInstance(dataBroker)) {
+ System.out.println("Delivering databroker");
+ res = databrokerAbsent ? Optional.empty() : Optional.of(dataBroker);
+ } else if (service.isInstance(rpcConsumerRegistry)) {
+ System.out.println("Delivering RpcConsumerRegistryMock");
+ res = Optional.of(rpcConsumerRegistry);
+ } else if (service.isInstance(setReadTransaction)) {
+ System.out.println("Delivering notificationService");
+ res = Optional.of(setReadTransaction);
+ } else {
+ System.out.println("Delivering no service");
+ res = Optional.empty();
+ }
+ return (Optional<T>) res;
+ }
+
+ public void setDatabrokerAbsent( boolean state) {
+ this.databrokerAbsent = state;
+ }
+
+ public DataBroker getDataBroker() {
+ return dataBroker;
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/MountPointServiceMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/MountPointServiceMock.java
new file mode 100644
index 0000000..1270196
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/MountPointServiceMock.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import java.util.Optional;
+import org.opendaylight.mdsal.binding.api.MountPoint;
+import org.opendaylight.mdsal.binding.api.MountPointService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * @author herbert
+ *
+ */
+public class MountPointServiceMock implements MountPointService {
+
+ private final MountPointMock mountpoint;
+
+ public MountPointServiceMock(MountPointMock mountpoint) {
+ this.mountpoint = mountpoint;
+ }
+
+ @Override
+ public Optional<MountPoint> getMountPoint(InstanceIdentifier<?> mountPoint) {
+
+ Optional<MountPoint> optional = Optional.of(mountpoint);
+ return optional;
+ }
+
+ @Override
+ public <T extends MountPointListener> ListenerRegistration<T> registerListener(InstanceIdentifier<?> path,
+ T listener) {
+ return null;
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/NotificationPublishServiceMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/NotificationPublishServiceMock.java
new file mode 100644
index 0000000..0564c56
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/NotificationPublishServiceMock.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.TimeUnit;
+import org.opendaylight.mdsal.binding.api.NotificationPublishService;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public class NotificationPublishServiceMock implements NotificationPublishService {
+
+ @Override
+ public ListenableFuture<?> offerNotification(Notification notification) {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<?> offerNotification(Notification notification, int timeout, TimeUnit unit)
+ throws InterruptedException {
+ return null;
+ }
+
+ @Override
+ public void putNotification(Notification notification) throws InterruptedException {
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/RpcConsumerRegistryMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/RpcConsumerRegistryMock.java
new file mode 100644
index 0000000..7e48ff2
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/RpcConsumerRegistryMock.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt sdnr-wt-devicemanager-provider
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public class RpcConsumerRegistryMock implements RpcConsumerRegistry {
+
+ @Override
+ public <T extends RpcService> T getRpcService(Class<T> serviceInterface) {
+ return null;
+ }
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/RpcProviderRegistryMock.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/RpcProviderRegistryMock.java
new file mode 100644
index 0000000..fbcb21d
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/mock/RpcProviderRegistryMock.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk feature sdnr wt
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock;
+
+import java.util.Set;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public class RpcProviderRegistryMock implements RpcProviderService {
+
+ @Override
+ public <S extends RpcService, T extends S> ObjectRegistration<T> registerRpcImplementation(Class<S> type,
+ T implementation) {
+ return null;
+ }
+
+ @Override
+ public <S extends RpcService, T extends S> ObjectRegistration<T> registerRpcImplementation(Class<S> type,
+ T implementation, Set<InstanceIdentifier<?>> paths) {
+ return null;
+ }
+
+
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/resources/captured-akka.conf b/sdnr/wt/netconfnode-state-service/provider/src/test/resources/captured-akka.conf
new file mode 100644
index 0000000..8489f09
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/resources/captured-akka.conf
@@ -0,0 +1,72 @@
+
+odl-cluster-data {
+
+ akka {
+ loglevel = ""
+ remote {
+ netty.tcp {
+ hostname = "zltcdyh1arbc02.2f0377.dyh1a.tci.att.com"
+ port = 2550
+ }
+ }
+ actor {
+ debug{
+ autoreceive = on
+ lifecycle = on
+ unhandled = on
+ fsm = on
+ event-stream = on
+ }
+ }
+ cluster {
+ seed-nodes = ["akka.tcp://opendaylight-cluster-data@zltcdyh1arbc01.2f0377.dyh1a.tci.att.com:2550", "akka.tcp://opendaylight-cluster-data@zltcdyh1arbc02.2f0377.dyh1a.tci.att.com:2550", "akka.tcp://opendaylight-cluster-data@zltcdyh1arbc03.2f0377.dyh1a.tci.att.com:2550", "akka.tcp://opendaylight-cluster-data@zltcdyh1brbc01.f84e7a.dyh1b.tci.att.com:2550", "akka.tcp://opendaylight-cluster-data@zltcdyh1brbc02.f84e7a.dyh1b.tci.att.com:2550", "akka.tcp://opendaylight-cluster-data@zltcdyh1brbc03.f84e7a.dyh1b.tci.att.com:2550"]
+ seed-node-timeout = 15s
+ roles = ["member-2"]
+
+ }
+ persistence {
+ journal-plugin-fallback {
+ circuit-breaker {
+ max-failures = 10
+ call-timeout = 60s
+ reset-timeout = 30s
+ }
+ }
+ }
+ }
+}
+
+odl-cluster-rpc {
+
+ akka {
+ loglevel = ""
+ remote {
+ netty.tcp {
+ hostname = "zltcdyh1arbc02.2f0377.dyh1a.tci.att.com"
+ port = 2551
+ }
+ }
+ actor {
+ debug{
+ autoreceive = on
+ lifecycle = on
+ unhandled = on
+ fsm = on
+ event-stream = on
+ }
+ }
+ cluster {
+ seed-nodes = ["akka.tcp://odl-cluster-rpc@zltcdyh1arbc01.2f0377.dyh1a.tci.att.com:2551", "akka.tcp://odl-cluster-rpc@zltcdyh1arbc02.2f0377.dyh1a.tci.att.com:2551", "akka.tcp://odl-cluster-rpc@zltcdyh1arbc03.2f0377.dyh1a.tci.att.com:2551", "akka.tcp://odl-cluster-rpc@zltcdyh1brbc01.f84e7a.dyh1b.tci.att.com:2551", "akka.tcp://odl-cluster-rpc@zltcdyh1brbc02.f84e7a.dyh1b.tci.att.com:2551", "akka.tcp://odl-cluster-rpc@zltcdyh1brbc03.f84e7a.dyh1b.tci.att.com:2551"]
+ seed-node-timeout = 15s
+ }
+ persistence {
+ journal-plugin-fallback {
+ circuit-breaker {
+ max-failures = 10
+ call-timeout = 60s
+ reset-timeout = 30s
+ }
+ }
+ }
+ }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/resources/simplelogger.properties b/sdnr/wt/netconfnode-state-service/provider/src/test/resources/simplelogger.properties
new file mode 100644
index 0000000..2eb3eb7
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/resources/simplelogger.properties
@@ -0,0 +1,38 @@
+# SLF4J's SimpleLogger configuration file
+# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
+
+# Default logging detail level for all instances of SimpleLogger.
+# Must be one of ("trace", "debug", "info", "warn", or "error").
+# If not specified, defaults to "info".
+org.slf4j.simpleLogger.defaultLogLevel=info
+
+# Logging detail level for a SimpleLogger instance named "xxx.yyy.zzz".
+# Must be one of ("trace", "debug", "info", "warn", or "error").
+# If not specified, the default logging detail level is used.
+# org.slf4j.simpleLogger.log.xxx.yyy=debug
+org.slf4j.simpleLogger.log.org.onap.ccsdk.features.sdnr.wt.devicemanager=info
+org.slf4j.simpleLogger.log.org.onap.ccsdk.features.sdnr.wt.devicemanager.archiveservice=info
+org.slf4j.simpleLogger.log.org.onap.ccsdk.features.sdnr.wt.devicemanager.base.internalTypes.Resources=info
+org.slf4j.simpleLogger.log.org.onap.ccsdk.features.sdnr.wt.devicemanager.base.netconf.container=info
+
+# Set to true if you want the current date and time to be included in output messages.
+# Default is false, and will output the number of milliseconds elapsed since startup.
+#org.slf4j.simpleLogger.showDateTime=false
+
+# The date and time format to be used in the output messages.
+# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
+# If the format is not specified or is invalid, the default format is used.
+# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
+#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
+
+# Set to true if you want to output the current thread name.
+# Defaults to true.
+#org.slf4j.simpleLogger.showThreadName=true
+
+# Set to true if you want the Logger instance name to be included in output messages.
+# Defaults to true.
+#org.slf4j.simpleLogger.showLogName=true
+
+# Set to true if you want the last component of the name to be included in output messages.
+# Defaults to false.
+#org.slf4j.simpleLogger.showShortLogName=false
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/resources/test.properties b/sdnr/wt/netconfnode-state-service/provider/src/test/resources/test.properties
new file mode 100644
index 0000000..de49c58
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/test/resources/test.properties
@@ -0,0 +1,55 @@
+[dcae]
+dcaeUserCredentials=admin:admin
+dcaeUrl=off
+dcaeHeartbeatPeriodSeconds=120
+dcaeTestCollector=no
+
+[aots]
+userPassword=passwd
+soapurladd=off
+soapaddtimeout=10
+soapinqtimeout=20
+userName=user
+inqtemplate=inqreq.tmpl.xml
+assignedto=userid
+addtemplate=addreq.tmpl.xml
+severitypassthrough=critical,major,minor,warning
+systemuser=user
+prt-offset=1200
+soapurlinq=off
+#smtpHost=
+#smtpPort=
+#smtpUsername=
+#smtpPassword=
+#smtpSender=
+#smtpReceivers=
+
+[es]
+esCluster=sendateodl5
+#time limit to keep increasing data in database [in seconds]
+#60*60*24*30 (30days)
+esArchiveLimit=2592000
+#folder where removed data will be stored
+esArchiveFolder=./backup
+#interval to archive database [in seconds]
+#60*60*24 (1day)
+esArchiveInterval=86400
+
+[aai]
+#keep comment
+aaiHeaders=["X-TransactionId: 9999"]
+aaiUrl=http://localhost:81
+aaiUserCredentials=AAI:AAI
+aaiDeleteOnMountpointRemove=false
+aaiTrustAllCerts=false
+aaiApiVersion=aai/v13
+aaiPropertiesFile=aaiclient.properties
+aaiApplicationId=SDNR
+aaiPcks12ClientCertFile=/opt/logs/externals/data/stores/keystore.client.p12
+aaiPcks12ClientCertPassphrase=adminadmin
+aaiClientConnectionTimeout=30000
+
+[pm]
+pmCluster=sendateodl5
+pmEnabled=true
+