summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/netconfnode-state-service/provider/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/netconfnode-state-service/provider/src/main')
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java586
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java86
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java137
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java81
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java91
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java45
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java162
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java126
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java27
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml56
-rw-r--r--sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties3
11 files changed, 1400 insertions, 0 deletions
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 000000000..0af35e569
--- /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 000000000..d0ea0eb69
--- /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 000000000..bdde30828
--- /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 000000000..ef161ad12
--- /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 000000000..994ef548b
--- /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 000000000..478ed8394
--- /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 000000000..c25f3264b
--- /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 000000000..9215887ff
--- /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 000000000..1434cf41a
--- /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 000000000..46930ac9e
--- /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 000000000..80373399e
--- /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}