From f7cc6a1daa39f583494dc0a71b89e1a1317a0a2b Mon Sep 17 00:00:00 2001 From: Ravi Pendurty Date: Wed, 3 Feb 2021 14:43:58 +0100 Subject: Migrate websocketmanager and netconfnode-state-service Migrate websocketmanager and netconfnode-state-service to Aluminium Issue-ID: CCSDK-3131 Signed-off-by: Ravi Pendurty Change-Id: If82aa071b8187f6cbd02f187d93b61a15463d718 Signed-off-by: Ravi Pendurty --- .../impl/GenericTransactionUtils.java | 147 -------------- .../impl/NetconfAccessorImpl.java | 224 --------------------- .../impl/NetconfAccessorManager.java | 60 ------ .../impl/NetconfNodeStateServiceImpl.java | 117 +++++------ .../impl/access/NetconfAccessorImpl.java | 116 +++++++++++ .../impl/access/NetconfAccessorManager.java | 74 +++++++ .../impl/access/NetconfCommunicatorManager.java | 120 +++++++++++ .../access/binding/GenericTransactionUtils.java | 145 +++++++++++++ .../access/binding/NetconfBindingAccessorImpl.java | 85 ++++++++ .../binding/NetconfBindingNotificationsImpl.java | 130 ++++++++++++ .../impl/access/dom/CanNotConvertException.java | 44 ++++ .../impl/access/dom/DomContext.java | 50 +++++ .../impl/access/dom/DomParser.java | 60 ++++++ .../impl/access/dom/NetconfDomAccessorImpl.java | 161 +++++++++++++++ .../impl/conf/NetconfStateConfig.java | 18 +- .../provider/src/main/resources/example.json | 16 ++ .../org/opendaylight/blueprint/impl-blueprint.xml | 26 ++- .../provider/src/main/resources/sample.json | 20 ++ 18 files changed, 1099 insertions(+), 514 deletions(-) delete mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/GenericTransactionUtils.java delete mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java delete mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorImpl.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorManager.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfCommunicatorManager.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/GenericTransactionUtils.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingAccessorImpl.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingNotificationsImpl.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/CanNotConvertException.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomContext.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomParser.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/NetconfDomAccessorImpl.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/resources/example.json create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/resources/sample.json (limited to 'sdnr/wt/netconfnode-state-service/provider/src/main') diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/GenericTransactionUtils.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/GenericTransactionUtils.java deleted file mode 100644 index 755224027..000000000 --- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/GenericTransactionUtils.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * ============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 com.google.common.base.Preconditions; -import com.google.common.util.concurrent.FluentFuture; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; -import org.onap.ccsdk.features.sdnr.wt.common.util.StackTrace; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils; -import org.opendaylight.mdsal.binding.api.DataBroker; -import org.opendaylight.mdsal.binding.api.ReadTransaction; -import org.opendaylight.mdsal.common.api.LogicalDatastoreType; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class GenericTransactionUtils implements TransactionUtils { - static final Logger LOG = LoggerFactory.getLogger(GenericTransactionUtils.class); - - /** - * Deliver the data back or null. Warning - * - * @param SubType of the DataObject to be handled - * @param dataBroker for accessing data - * @param dataStoreType to address datastore - * @param iid id to access data - * @return null or object - */ - @Override - @Nullable - public T readData(DataBroker dataBroker, LogicalDatastoreType dataStoreType, - InstanceIdentifier iid) { - - AtomicBoolean noErrorIndication = new AtomicBoolean(); - AtomicReference statusText = new AtomicReference<>(); - - @Nullable - T obj = readDataOptionalWithStatus(dataBroker, dataStoreType, iid, noErrorIndication, statusText); - - if (!noErrorIndication.get()) { - LOG.warn("Read transaction for identifier " + iid + " failed with status " + statusText.get()); - } - - return obj; - } - - /** - * Deliver the data back or null - * - * @param SubType of the DataObject to be handled - * @param dataBroker for accessing data - * @param dataStoreType to address datastore - * @param iid id to access data - * @param noErrorIndication (Output) true if data could be read and are available and is not null - * @param statusIndicator (Output) String with status indications during the read. - * @return null or object - */ - @Override - @SuppressWarnings("null") - public @Nullable T readDataOptionalWithStatus(DataBroker dataBroker, - LogicalDatastoreType dataStoreType, InstanceIdentifier iid, AtomicBoolean noErrorIndication, - AtomicReference statusIndicator) { - - @Nullable - T data = null; - noErrorIndication.set(false); - - statusIndicator.set("Preconditions"); - Preconditions.checkNotNull(dataBroker); - - int retry = 0; - int retryDelayMilliseconds = 2000; - int maxRetries = 0; // 0 no Retry - - do { - if (retry > 0) { - try { - LOG.debug("Sleep {}ms", retryDelayMilliseconds); - Thread.sleep(retryDelayMilliseconds); - } catch (InterruptedException e) { - LOG.debug("Sleep interrupted", e); - Thread.currentThread().interrupt(); - } - } - - LOG.debug("Sending message with retry {} ", retry); - statusIndicator.set("Create Read Transaction"); - ReadTransaction readTransaction = dataBroker.newReadOnlyTransaction(); - try { - @NonNull - FluentFuture> od = readTransaction.read(dataStoreType, iid); - statusIndicator.set("Read done"); - if (od != null) { - statusIndicator.set("Unwrap checkFuture done"); - Optional optionalData = od.get(); - if (optionalData != null) { - statusIndicator.set("Unwrap optional done"); - data = optionalData.orElse(null); - statusIndicator.set("Read transaction done"); - noErrorIndication.set(true); - } else { - statusIndicator.set("optional Data is null"); - } - } else { - statusIndicator.set("od feature is null"); - } - } catch (CancellationException | ExecutionException | InterruptedException | NoSuchElementException e) { - statusIndicator.set(StackTrace.toString(e)); - if (e instanceof InterruptedException) { - Thread.currentThread().interrupt(); - } - LOG.debug("Exception during read", e); - } - - } while (noErrorIndication.get() == false && retry++ < maxRetries); - - LOG.debug("stage 2 noErrorIndication {} status text {}", noErrorIndication.get(), statusIndicator.get()); - - return data; - } - - -} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java deleted file mode 100644 index 65b8e6f56..000000000 --- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * ============LICENSE_START======================================================================== - * ONAP : ccsdk feature sdnr wt - * ================================================================================================= - * Copyright (C) 2020 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 com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; -import java.util.List; -import java.util.Optional; -import javax.annotation.Nonnull; -import org.onap.ccsdk.features.sdnr.wt.common.YangHelper; -import org.eclipse.jdt.annotation.NonNull; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.Capabilities; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils; -import org.opendaylight.mdsal.binding.api.DataBroker; -import org.opendaylight.mdsal.binding.api.MountPoint; -import org.opendaylight.mdsal.binding.api.NotificationService; -import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry; -import org.opendaylight.mdsal.common.api.LogicalDatastoreType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionOutput; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.streams.Stream; -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.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.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.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.NotificationListener; -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; - -public class NetconfAccessorImpl implements NetconfAccessor { - - private static final Logger log = LoggerFactory.getLogger(NetconfAccessorImpl.class); - - private static final @NonNull InstanceIdentifier NETCONF_TOPO_IID = - InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, - new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); - - private final NodeId nodeId; - private final DataBroker dataBroker; - private final TransactionUtils transactionUtils; - private final MountPoint mountpoint; - private final NetconfNode netconfNode; - private final Capabilities capabilities; - - /** - * Contains all data to access and manage netconf device - * - * @param nodeId of managed netconf node - * @param netconfNode information - * @param dataBroker to access node - * @param mountpoint of netconfNode - * @param transactionUtils with read an write functions - */ - public NetconfAccessorImpl(NodeId nodeId, NetconfNode netconfNode, DataBroker dataBroker, MountPoint mountpoint, - TransactionUtils transactionUtils) { - super(); - this.nodeId = nodeId; - this.netconfNode = netconfNode; - this.dataBroker = dataBroker; - this.mountpoint = mountpoint; - this.transactionUtils = transactionUtils; - - ConnectionStatus csts = netconfNode != null ? netconfNode.getConnectionStatus() : null; - if (csts == null) { - throw new IllegalStateException(String.format("connection status for %s is not connected", nodeId)); - } - Capabilities tmp = Capabilities.getAvailableCapabilities(netconfNode); - if (tmp.getCapabilities().size() <= 0) { - throw new IllegalStateException(String.format("no capabilities found for %s", nodeId)); - } - this.capabilities = tmp; - } - - /** - * @param nodeId with uuid of managed netconf node - * @param dataBroker to access node - */ - public NetconfAccessorImpl(String nodeId, NetconfNode netconfNode, DataBroker dataBroker, MountPoint mountpoint, - TransactionUtils transactionUtils) { - this(new NodeId(nodeId), netconfNode, dataBroker, mountpoint, transactionUtils); - } - - @Override - public NodeId getNodeId() { - return nodeId; - } - - @Override - public DataBroker getDataBroker() { - return dataBroker; - } - - @Override - public MountPoint getMountpoint() { - return mountpoint; - } - - @Override - public TransactionUtils getTransactionUtils() { - return transactionUtils; - } - - @Override - public NetconfNode getNetconfNode() { - return netconfNode; - } - - @Override - public Capabilities getCapabilites() { - return capabilities; - } - - @Override - public @NonNull ListenerRegistration doRegisterNotificationListener( - @NonNull T listener) { - log.info("Begin register listener for Mountpoint {}", mountpoint.getIdentifier().toString()); - final Optional optionalNotificationService = - mountpoint.getService(NotificationService.class); - final NotificationService notificationService = optionalNotificationService.get(); - final ListenerRegistration ranListenerRegistration = - notificationService.registerNotificationListener(listener); - log.info("End registration listener for Mountpoint {} Listener: {} Result: {}", - mountpoint.getIdentifier().toString(), optionalNotificationService, ranListenerRegistration); - return ranListenerRegistration; - } - - @Override - public ListenableFuture> registerNotificationsStream(String streamName) { - - String failMessage = ""; - final Optional optionalRpcConsumerService = - mountpoint.getService(RpcConsumerRegistry.class); - if (optionalRpcConsumerService.isPresent()) { - final RpcConsumerRegistry rpcConsumerRegitry = optionalRpcConsumerService.get(); - @Nonnull - final NotificationsService rpcService = rpcConsumerRegitry.getRpcService(NotificationsService.class); - - final CreateSubscriptionInputBuilder createSubscriptionInputBuilder = new CreateSubscriptionInputBuilder(); - createSubscriptionInputBuilder.setStream(new StreamNameType(streamName)); - log.info("Event listener triggering notification stream {} for node {}", streamName, nodeId); - try { - CreateSubscriptionInput createSubscriptionInput = createSubscriptionInputBuilder.build(); - if (createSubscriptionInput == null) { - failMessage = "createSubscriptionInput is null for mountpoint " + nodeId; - } else { - return rpcService.createSubscription(createSubscriptionInput); - } - } catch (NullPointerException e) { - failMessage = "createSubscription failed"; - } - } else { - failMessage = "No RpcConsumerRegistry avaialble."; - } - log.warn(failMessage); - RpcResultBuilder result = RpcResultBuilder.failed(); - result.withError(ErrorType.APPLICATION, failMessage); - SettableFuture> res = SettableFuture.create(); - res.set(result.build()); - return res; - } - - @Override - public void registerNotificationsStream(List streamList) { - for (Stream stream : streamList) { - log.info("Stream Name = {}, Stream Description = {}", stream.getName().getValue(), stream.getDescription()); - if (!(stream.getName().getValue().equals(NetconfAccessor.DefaultNotificationsStream))) // Since this stream is already registered - registerNotificationsStream(stream.getName().getValue()); - } - } - - /** - * check if nc-notifications.yang is supported by the device - */ - @Override - public boolean isNCNotificationsSupported() { - Capabilities capabilities = getCapabilites(); - if (capabilities.isSupportingNamespace(Netconf.QNAME)) { - return true; - } - return false; - } - - @Override - public List getNotificationStreams() { - final Class netconfClazz = Netconf.class; - InstanceIdentifier streamsIID = InstanceIdentifier.builder(netconfClazz).build(); - - Netconf res = getTransactionUtils().readData(getDataBroker(), LogicalDatastoreType.OPERATIONAL, streamsIID); - Streams streams = res.getStreams(); - return YangHelper.getList(streams.getStream()); - } - - -} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java deleted file mode 100644 index 9fad32477..000000000 --- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ============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.Objects; -import java.util.concurrent.ConcurrentHashMap; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils; -import org.opendaylight.mdsal.binding.api.DataBroker; -import org.opendaylight.mdsal.binding.api.MountPoint; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NetconfAccessorManager { - - private static final Logger log = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class); - - private static final TransactionUtils TRANSACTIONUTILS = new GenericTransactionUtils(); - private final ConcurrentHashMap accessorList; - - public NetconfAccessorManager() { - accessorList = new ConcurrentHashMap<>(); - } - - public NetconfAccessor getAccessor(NodeId nNodeId, NetconfNode netconfNode, DataBroker netconfNodeDataBroker, - MountPoint mountPoint) { - NetconfAccessorImpl res = - new NetconfAccessorImpl(nNodeId, netconfNode, netconfNodeDataBroker, mountPoint, TRANSACTIONUTILS); - NetconfAccessor previouse = accessorList.put(nNodeId.getValue(), res); - if (Objects.nonNull(previouse)) { - log.warn("Accessor with name already available. Replaced with new one."); - } - return res; - } - - public boolean containes(NodeId nNodeId) { - return accessorList.containsKey(nNodeId.getValue()); - } - - public void removeAccessor(NodeId nNodeId) { - accessorList.remove(nNodeId.getValue()); - } -} 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 index 15a274dc4..92ce34b16 100644 --- 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 @@ -21,12 +21,12 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.annotation.Nullable; - import org.eclipse.jdt.annotation.NonNull; import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation; import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener; @@ -37,6 +37,9 @@ import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnec 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.access.NetconfAccessorManager; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.NetconfCommunicatorManager; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.DomContext; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.NetconfStateConfig; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.AkkaConfig; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.ClusterConfig; @@ -50,11 +53,12 @@ import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationTyp 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.binding.dom.codec.api.BindingNormalizedNodeSerializer; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMMountPointService; 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; @@ -69,9 +73,10 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. 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.opendaylight.yangtools.yang.model.parser.api.YangParserException; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -80,21 +85,18 @@ public class NetconfNodeStateServiceImpl 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"; - @SuppressWarnings("null") private static final @NonNull InstanceIdentifier NETCONF_TOPO_IID = InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); - @SuppressWarnings("null") private static final @NonNull InstanceIdentifier 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 NETCONF_NODE_TOPO_TREE_ID = + private static final @NonNull DataTreeIdentifier NETCONF_NODE_TOPO_TREE_ID = DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID); // Name of ODL controller NETCONF instance @@ -103,12 +105,15 @@ public class NetconfNodeStateServiceImpl // -- OSGi services, provided private DataBroker dataBroker; private MountPointService mountPointService; + private DOMMountPointService domMountPointService; private RpcProviderService rpcProviderRegistry; private IEntityDataProvider iEntityDataProvider; @SuppressWarnings("unused") private NotificationPublishService notificationPublishService; @SuppressWarnings("unused") private ClusterSingletonServiceProvider clusterSingletonServiceProvider; + private YangParserFactory yangParserFactory; + private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer; // -- Parameter private ListenerRegistration listenerL1; @@ -122,7 +127,7 @@ public class NetconfNodeStateServiceImpl private Boolean initializationSuccessful; /** Manager accessor objects for connection **/ - private final NetconfAccessorManager accessorManager; + private NetconfAccessorManager accessorManager; /** List of all registered listeners **/ private final List netconfNodeConnectListenerList; @@ -146,6 +151,8 @@ public class NetconfNodeStateServiceImpl private ConfigurationFileRepresentation configFileRepresentation; private NetconfStateConfig config; + private NetconfCommunicatorManager netconfCommunicatorManager; + private DomContext domContext; /** Blueprint **/ public NetconfNodeStateServiceImpl() { @@ -153,9 +160,12 @@ public class NetconfNodeStateServiceImpl this.dataBroker = null; this.mountPointService = null; + this.domMountPointService = null; this.rpcProviderRegistry = null; this.notificationPublishService = null; this.clusterSingletonServiceProvider = null; + this.yangParserFactory = null; + this.domContext = null; this.listenerL1 = null; this.listenerL2 = null; @@ -163,7 +173,7 @@ public class NetconfNodeStateServiceImpl this.netconfNodeConnectListenerList = new CopyOnWriteArrayList<>(); this.netconfNodeStateListenerList = new CopyOnWriteArrayList<>(); this.vesNotificationListenerList = new CopyOnWriteArrayList<>(); - this.accessorManager = new NetconfAccessorManager(); + this.accessorManager = null; this.handlingPool = new HashMap<>(); } @@ -184,6 +194,10 @@ public class NetconfNodeStateServiceImpl this.mountPointService = mountPointService; } + public void setDomMountPointService(DOMMountPointService domMountPointService) { + this.domMountPointService = domMountPointService; + } + public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) { this.clusterSingletonServiceProvider = clusterSingletonService; } @@ -192,11 +206,22 @@ public class NetconfNodeStateServiceImpl this.iEntityDataProvider = iEntityDataProvider; } - /** Blueprint initialization **/ + public void setYangParserFactory(YangParserFactory yangParserFactory) { + this.yangParserFactory = yangParserFactory; + } + + public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) { + this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer; + } + + /** Blueprint initialization + * @throws YangParserException **/ public void init() { LOG.info("Session Initiated start {}", APPLICATION_NAME); - + this.domContext = new DomContext(this.yangParserFactory, this.bindingNormalizedNodeSerializer); + this.netconfCommunicatorManager = new NetconfCommunicatorManager(mountPointService, domMountPointService, domContext); + this.accessorManager = new NetconfAccessorManager(netconfCommunicatorManager, domContext); // Start RPC Service this.rpcApiService = new NetconfnodeStateServiceRpcApiImpl(rpcProviderRegistry, vesNotificationListenerList); // Get configuration @@ -237,13 +262,12 @@ public class NetconfNodeStateServiceImpl close(); } - /** - * Getter - * - * @return NetconfnodeStateServiceRpcApiImpl - */ + public DomContext getDomContext() { + return Objects.requireNonNull(domContext, "Initialization not completed for domContext" ); + } + public NetconfnodeStateServiceRpcApiImpl getNetconfnodeStateServiceRpcApiImpl() { - return rpcApiService; + return Objects.requireNonNull(rpcApiService, "Initialization not completed for rpcApiService" ); } @Override @@ -339,7 +363,7 @@ public class NetconfNodeStateServiceImpl /** * Indication if init() of this bundle successfully done. - * + * * @return true if init() was successful. False if not done or not successful. */ public boolean isInitializationSuccessful() { @@ -353,7 +377,7 @@ public class NetconfNodeStateServiceImpl /** * 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 */ @@ -378,50 +402,26 @@ public class NetconfNodeStateServiceImpl boolean isNetconfNodeMaster = isNetconfNodeMaster(netconfNode); LOG.info("isNetconfNodeMaster indication {} for mountpoint {}", isNetconfNodeMaster, mountPointNodeName); if (isNetconfNodeMaster) { + NetconfAccessor acessor = accessorManager.getAccessor(nNodeId, netconfNode); + /* + * --> Call Listers for onConnect() Indication + for (all) + */ + netconfNodeConnectListenerList.forEach(item -> { + try { + item.onEnterConnected(acessor); + } catch (Exception e) { + LOG.info("Exception during onEnterConnected listener call", e); + } + }); - InstanceIdentifier instanceIdentifier = - NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName))); - - Optional optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier); - if (!optionalMountPoint.isPresent()) { - LOG.warn("No mountpoint available for Netconf device :: Name : {} ", mountPointNodeName); - } else { - // Mountpoint is present for sure - MountPoint mountPoint = optionalMountPoint.get(); - // BindingDOMDataBrokerAdapter.BUILDER_FACTORY; - LOG.info("Mountpoint with id: {} class:{}", mountPoint.getIdentifier(), - mountPoint.getClass().getName()); - - Optional 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(); - NetconfAccessor acessor = - accessorManager.getAccessor(nNodeId, netconfNode, netconfNodeDataBroker, mountPoint); - /* - * --> Call Listers for onConnect() Indication - for (all) - */ - netconfNodeConnectListenerList.forEach(item -> { - try { - item.onEnterConnected(acessor); - } catch (Exception e) { - LOG.info("Exception during onEnterConnected listener call", e); - } - }); - - LOG.info("Connect indication forwarded for {}", mountPointNodeName); - } - } + LOG.info("Connect indication forwarded for {}", mountPointNodeName); } } /** * Leave the connected status to a non connected or removed status for master mountpoint - * + * * @param action that occurred * @param nNodeId id of the mountpoint * @param netconfNode mountpoint contents or not available on remove @@ -651,7 +651,6 @@ public class NetconfNodeStateServiceImpl 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(); @@ -664,6 +663,8 @@ public class NetconfNodeStateServiceImpl return true; } + + @Override public void onConfigChanged() { this.handleDataTreeAsync = this.config.handleAsync(); diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorImpl.java new file mode 100644 index 000000000..5ff6caf56 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorImpl.java @@ -0,0 +1,116 @@ +/* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2020 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.access; + +import java.util.Objects; +import java.util.Optional; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.Capabilities; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfBindingAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfDomAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.DomContext; +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.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfAccessorImpl implements NetconfAccessor { + + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory.getLogger(NetconfAccessorImpl.class); + + private final NodeId nodeId; + private final NetconfNode netconfNode; + private final Capabilities capabilities; + private final NetconfCommunicatorManager netconfCommunicatorManager; + private final DomContext domContext; + + /** + * Contains all data to access and manage netconf device + * + * @param netconfCommunicatorManager + * + * @param nodeId of managed netconf node + * @param netconfNode information + * @param domContext + * @param dataBroker to access node + * @param mountpoint of netconfNode + */ + public NetconfAccessorImpl(NodeId nodeId, NetconfNode netconfNode, + NetconfCommunicatorManager netconfCommunicatorManager, DomContext domContext) { + super(); + this.nodeId = Objects.requireNonNull(nodeId); + this.netconfNode = Objects.requireNonNull(netconfNode); + this.netconfCommunicatorManager = Objects.requireNonNull(netconfCommunicatorManager); + this.domContext = Objects.requireNonNull(domContext); + + ConnectionStatus csts = netconfNode != null ? netconfNode.getConnectionStatus() : null; + if (csts == null) { + throw new IllegalStateException(String.format("connection status for %s is not connected", nodeId)); + } + Capabilities tmp = Capabilities.getAvailableCapabilities(netconfNode); + if (tmp.getCapabilities().size() <= 0) { + throw new IllegalStateException(String.format("no capabilities found for %s", nodeId)); + } + this.capabilities = tmp; + } + + /** + * @param nodeId with uuid of managed netconf node + * @param dataBroker to access node + */ + public NetconfAccessorImpl(String nodeId, NetconfNode netconfNode, + NetconfCommunicatorManager netconfCommunicatorManager, DomContext domContext) { + this(new NodeId(nodeId), netconfNode, netconfCommunicatorManager, domContext); + } + + protected NetconfAccessorImpl(NetconfAccessorImpl accessor) { + this.nodeId = accessor.nodeId; + this.netconfNode = accessor.netconfNode; + this.capabilities = accessor.capabilities; + this.netconfCommunicatorManager = accessor.netconfCommunicatorManager; + this.domContext = accessor.domContext; + } + + @Override + public NodeId getNodeId() { + return nodeId; + } + + @Override + public NetconfNode getNetconfNode() { + return netconfNode; + } + + @Override + public Capabilities getCapabilites() { + return capabilities; + } + + @Override + public Optional getNetconfBindingAccessor() { + return netconfCommunicatorManager.getNetconfBindingAccessor(this); + } + + @Override + public Optional getNetconfDomAccessor() { + return netconfCommunicatorManager.getNetconfDomAccessor(this); + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorManager.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorManager.java new file mode 100644 index 000000000..280193402 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfAccessorManager.java @@ -0,0 +1,74 @@ +/* + * ============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.access; + +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import org.eclipse.jdt.annotation.NonNull; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.NetconfNodeStateServiceImpl; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.DomContext; +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.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.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.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfAccessorManager { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class); + + private static final @NonNull InstanceIdentifier NETCONF_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, + new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); + + private final ConcurrentHashMap accessorList; + private final NetconfCommunicatorManager netconfCommunicatorManager; + private final DomContext domContext; + + public NetconfAccessorManager(NetconfCommunicatorManager netconfCommunicatorManager, DomContext domContext) { + this.netconfCommunicatorManager = Objects.requireNonNull(netconfCommunicatorManager); + this.domContext = Objects.requireNonNull(domContext); + this.accessorList = new ConcurrentHashMap<>(); + } + + public NetconfAccessor getAccessor(NodeId nNodeId, NetconfNode netconfNode) { + NetconfAccessor res = new NetconfAccessorImpl(nNodeId, netconfNode, netconfCommunicatorManager, domContext); + NetconfAccessor previouse = accessorList.put(nNodeId, res); + if (Objects.nonNull(previouse)) { + LOG.warn("Accessor with name already available. Replaced with new one."); + } + return res; + } + + public boolean containes(NodeId nNodeId) { + return accessorList.containsKey(nNodeId); + } + + public void removeAccessor(NodeId nNodeId) { + accessorList.remove(nNodeId); + } + + + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfCommunicatorManager.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfCommunicatorManager.java new file mode 100644 index 000000000..bff29acc1 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/NetconfCommunicatorManager.java @@ -0,0 +1,120 @@ +/* + * ============LICENSE_START======================================================= + * ONAP : ccsdk features + * ================================================================================ + * Copyright (C) 2020 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.access; + +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfBindingAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfDomAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.binding.NetconfBindingNotificationsImpl; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.DomContext; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.NetconfDomAccessorImpl; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.MountPoint; +import org.opendaylight.mdsal.binding.api.MountPointService; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; +import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMMountPointService; +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.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.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfCommunicatorManager { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfCommunicatorManager.class); + + private static final @NonNull InstanceIdentifier NETCONF_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, + new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); + + private static final @NonNull InstanceIdentifier NETCONF_NODE_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))) + .child(Node.class); + + private final MountPointService mountPointService; + private final DOMMountPointService domMountPointService; + private final DomContext domContext; + + public NetconfCommunicatorManager(MountPointService mountPointService, DOMMountPointService domMountPointService, + DomContext domContext) { + super(); + this.mountPointService = mountPointService; + this.domMountPointService = domMountPointService; + this.domContext = domContext; + } + + public Optional getNetconfBindingAccessor(NetconfAccessorImpl accessor) { + String mountPointNodeName = accessor.getNodeId().getValue(); + InstanceIdentifier instanceIdentifier = + NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName))); + + final Optional optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier); + if (!optionalMountPoint.isPresent()) { + LOG.warn("No mountpoint available for Netconf device :: Name : {} ", mountPointNodeName); + } else { + final MountPoint mountPoint = optionalMountPoint.get(); + + LOG.info("Mountpoint with id: {} class:{}", mountPoint.getIdentifier(), mountPoint.getClass().getName()); + + Optional optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class); + + if (!optionalNetconfNodeDatabroker.isPresent()) { + LOG.info("Slave mountpoint {} without databroker", mountPointNodeName); + } else { + LOG.info("Master mountpoint {}", mountPointNodeName); + return Optional.of(new NetconfBindingNotificationsImpl(accessor, optionalNetconfNodeDatabroker.get(), mountPoint)); + } + } + return Optional.empty(); + } + + public Optional getNetconfDomAccessor(NetconfAccessorImpl accessor) { + + final YangInstanceIdentifier mountpointPath = YangInstanceIdentifier.builder().node(NetworkTopology.QNAME) + .node(Topology.QNAME) + .nodeWithKey(Topology.QNAME, QName.create(Topology.QNAME, "topology-id").intern(), "topology-netconf") + .node(Node.QNAME) + .nodeWithKey(Node.QNAME, QName.create(Node.QNAME, "node-id").intern(), accessor.getNodeId().getValue()).build(); + final Optional mountPoint = domMountPointService.getMountPoint(mountpointPath); + if (mountPoint.isEmpty()) { + return Optional.empty(); + } + + final Optional domDataBroker = mountPoint.get().getService(DOMDataBroker.class); + if (domDataBroker.isPresent()) { + return Optional.of(new NetconfDomAccessorImpl(accessor, domDataBroker.get(), mountPoint.get(), domContext)); + } + return Optional.empty(); + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/GenericTransactionUtils.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/GenericTransactionUtils.java new file mode 100644 index 000000000..282048453 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/GenericTransactionUtils.java @@ -0,0 +1,145 @@ +/* + * ============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.access.binding; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.FluentFuture; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.onap.ccsdk.features.sdnr.wt.common.util.StackTrace; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class GenericTransactionUtils implements TransactionUtils { + static final Logger LOG = LoggerFactory.getLogger(GenericTransactionUtils.class); + + /** + * Deliver the data back or null. Warning + * + * @param SubType of the DataObject to be handled + * @param dataBroker for accessing data + * @param dataStoreType to address datastore + * @param iid id to access data + * @return null or object + */ + @Override + @Nullable + public T readData(DataBroker dataBroker, LogicalDatastoreType dataStoreType, + InstanceIdentifier iid) { + + AtomicBoolean noErrorIndication = new AtomicBoolean(); + AtomicReference statusText = new AtomicReference<>(); + + @Nullable + T obj = readDataOptionalWithStatus(dataBroker, dataStoreType, iid, noErrorIndication, statusText); + + if (!noErrorIndication.get()) { + LOG.warn("Read transaction for identifier " + iid + " failed with status " + statusText.get()); + } + + return obj; + } + + /** + * Deliver the data back or null + * + * @param SubType of the DataObject to be handled + * @param dataBroker for accessing data + * @param dataStoreType to address datastore + * @param iid id to access data + * @param noErrorIndication (Output) true if data could be read and are available and is not null + * @param statusIndicator (Output) String with status indications during the read. + * @return null or object + */ + @Override + public @Nullable T readDataOptionalWithStatus(DataBroker dataBroker, + LogicalDatastoreType dataStoreType, InstanceIdentifier iid, AtomicBoolean noErrorIndication, + AtomicReference statusIndicator) { + + @Nullable + T data = null; + noErrorIndication.set(false); + + statusIndicator.set("Preconditions"); + Preconditions.checkNotNull(dataBroker); + + int retry = 0; + int retryDelayMilliseconds = 2000; + int maxRetries = 0; // 0 no Retry + + do { + if (retry > 0) { + try { + LOG.debug("Sleep {}ms", retryDelayMilliseconds); + Thread.sleep(retryDelayMilliseconds); + } catch (InterruptedException e) { + LOG.debug("Sleep interrupted", e); + Thread.currentThread().interrupt(); + } + } + + LOG.debug("Sending message with retry {} ", retry); + statusIndicator.set("Create Read Transaction"); + ReadTransaction readTransaction = dataBroker.newReadOnlyTransaction(); + try { + @NonNull + FluentFuture> od = readTransaction.read(dataStoreType, iid); + statusIndicator.set("Read done"); + if (od != null) { + statusIndicator.set("Unwrap checkFuture done"); + Optional optionalData = od.get(); + if (optionalData != null) { + statusIndicator.set("Unwrap optional done"); + data = optionalData.orElse(null); + statusIndicator.set("Read transaction done"); + noErrorIndication.set(true); + } else { + statusIndicator.set("optional Data is null"); + } + } else { + statusIndicator.set("od feature is null"); + } + } catch (CancellationException | ExecutionException | InterruptedException | NoSuchElementException e) { + statusIndicator.set(StackTrace.toString(e)); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + LOG.debug("Exception during read", e); + } + + } while (noErrorIndication.get() == false && retry++ < maxRetries); + + LOG.debug("stage 2 noErrorIndication {} status text {}", noErrorIndication.get(), statusIndicator.get()); + + return data; + } + + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingAccessorImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingAccessorImpl.java new file mode 100644 index 000000000..9b9e96c15 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingAccessorImpl.java @@ -0,0 +1,85 @@ +/* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2020 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.access.binding; + +import java.util.Objects; +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfBindingAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.NetconfAccessorImpl; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.MountPoint; +import org.opendaylight.mdsal.binding.api.NotificationService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class NetconfBindingAccessorImpl extends NetconfAccessorImpl implements NetconfBindingAccessor { + + private static final Logger log = LoggerFactory.getLogger(NetconfBindingAccessorImpl.class); + + private final static GenericTransactionUtils GENERICTRANSACTIONUTILS = new GenericTransactionUtils(); + + private final DataBroker dataBroker; + private final MountPoint mountpoint; + + /** + * Contains all data to access and manage netconf device + * + * @param nodeId of managed netconf node + * @param netconfNode information + * @param dataBroker to access node + * @param mountpoint of netconfNode + */ + public NetconfBindingAccessorImpl(NetconfAccessorImpl accessor, DataBroker dataBroker, MountPoint mountpoint) { + super(accessor); + this.dataBroker = Objects.requireNonNull(dataBroker); + this.mountpoint = Objects.requireNonNull(mountpoint); + } + + @Override + public DataBroker getDataBroker() { + return dataBroker; + } + + @Override + public MountPoint getMountpoint() { + return mountpoint; + } + + @Override + public TransactionUtils getTransactionUtils() { + return GENERICTRANSACTIONUTILS; + } + + @Override + public @NonNull ListenerRegistration doRegisterNotificationListener( + @NonNull T listener) { + log.info("Begin register listener for Mountpoint {}", mountpoint.getIdentifier().toString()); + final Optional optionalNotificationService = + mountpoint.getService(NotificationService.class); + final NotificationService notificationService = optionalNotificationService.get(); + final ListenerRegistration ranListenerRegistration = + notificationService.registerNotificationListener(listener); + log.info("End registration listener for Mountpoint {} Listener: {} Result: {}", + mountpoint.getIdentifier().toString(), optionalNotificationService, ranListenerRegistration); + return ranListenerRegistration; + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingNotificationsImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingNotificationsImpl.java new file mode 100644 index 000000000..6716581a2 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/NetconfBindingNotificationsImpl.java @@ -0,0 +1,130 @@ +/* + * ============LICENSE_START======================================================= + * ONAP : ccsdk features + * ================================================================================ + * Copyright (C) 2020 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.access.binding; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import java.util.List; +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.onap.ccsdk.features.sdnr.wt.common.YangHelper; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNotifications; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.NetconfAccessorImpl; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.MountPoint; +import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionOutput; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.streams.Stream; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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; + +public class NetconfBindingNotificationsImpl extends NetconfBindingAccessorImpl implements NetconfNotifications { + + private static final Logger log = LoggerFactory.getLogger(NetconfAccessorImpl.class); + + public NetconfBindingNotificationsImpl(NetconfAccessorImpl accessor, DataBroker dataBroker, MountPoint mountpoint) { + super(accessor, dataBroker, mountpoint); + } + + @Override + public ListenableFuture> registerNotificationsStream(@NonNull String streamName) { + String failMessage = ""; + final Optional optionalRpcConsumerService = + getMountpoint().getService(RpcConsumerRegistry.class); + if (optionalRpcConsumerService.isPresent()) { + final NotificationsService rpcService = optionalRpcConsumerService.get().getRpcService(NotificationsService.class); + + final CreateSubscriptionInputBuilder createSubscriptionInputBuilder = new CreateSubscriptionInputBuilder(); + createSubscriptionInputBuilder.setStream(new StreamNameType(streamName)); + log.info("Event listener triggering notification stream {} for node {}", streamName, getNodeId()); + try { + CreateSubscriptionInput createSubscriptionInput = createSubscriptionInputBuilder.build(); + if (createSubscriptionInput == null) { + failMessage = "createSubscriptionInput is null for mountpoint " + getNodeId(); + } else { + return rpcService.createSubscription(createSubscriptionInput); + } + } catch (NullPointerException e) { + failMessage = "createSubscription failed"; + } + } else { + failMessage = "No RpcConsumerRegistry avaialble."; + } + log.warn(failMessage); + RpcResultBuilder result = RpcResultBuilder.failed(); + result.withError(ErrorType.APPLICATION, failMessage); + SettableFuture> future = SettableFuture.create(); + future.set(result.build()); + return future; + } + + @Override + public void registerNotificationsStream(List streamList) { + for (Stream stream : streamList) { + log.info("Stream Name = {}, Stream Description = {}", stream.getName().getValue(), stream.getDescription()); + if (!(stream.getName().getValue().equals(NetconfNotifications.DefaultNotificationsStream))) // Since this stream is already registered + registerNotificationsStream(stream.getName().getValue()); + } + } + + @Override + public boolean isNotificationsSupported() { + return false; + } + + + /** + * check if nc-notifications.yang is supported by the device + */ + @Override + public boolean isNCNotificationsSupported() { + return getCapabilites().isSupportingNamespace(Netconf.QNAME); + } + + @Override + public List getNotificationStreams() { + final Class netconfClazz = Netconf.class; + InstanceIdentifier streamsIID = InstanceIdentifier.builder(netconfClazz).build(); + + Netconf res = getTransactionUtils().readData(getDataBroker(), + LogicalDatastoreType.OPERATIONAL, streamsIID); + Streams streams = res.getStreams(); + return YangHelper.getList(streams.getStream()); + } + + @Override + public Optional getNotificationAccessor() { + return Optional.of(this); + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/CanNotConvertException.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/CanNotConvertException.java new file mode 100644 index 000000000..10ebc5a99 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/CanNotConvertException.java @@ -0,0 +1,44 @@ +/* + * ============LICENSE_START======================================================= + * ONAP : ccsdk features + * ================================================================================ + * Copyright (C) 2020 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.access.dom; + +public class CanNotConvertException extends Exception { + + private static final long serialVersionUID = 1L; + + public CanNotConvertException() { + super(); + } + + public CanNotConvertException(String message) { + super(message); + } + + public CanNotConvertException(String message, Throwable cause) { + super(message, cause); + } + + public CanNotConvertException(Throwable cause) { + super(cause); + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomContext.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomContext.java new file mode 100644 index 000000000..35eaa9fc8 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomContext.java @@ -0,0 +1,50 @@ +/* + * ============LICENSE_START======================================================= + * ONAP : ccsdk features + * ================================================================================ + * Copyright (C) 2020 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.access.dom; + +import java.util.Objects; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DomContext { + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory.getLogger(DomContext.class); + + private final YangParserFactory yangParserFactory; + private final BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer; + + public DomContext(YangParserFactory yangParserFactory, BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) { + this.yangParserFactory = Objects.requireNonNull(yangParserFactory); + this.bindingNormalizedNodeSerializer = Objects.requireNonNull(bindingNormalizedNodeSerializer); + } + + public BindingNormalizedNodeSerializer getBindingNormalizedNodeSerializer() { + return bindingNormalizedNodeSerializer; + } + + public YangParserFactory getYangParserFactory() { + return yangParserFactory; + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomParser.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomParser.java new file mode 100644 index 000000000..9bfa826bf --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/DomParser.java @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * ONAP : ccsdk features + * ================================================================================ + * Copyright (C) 2020 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.access.dom; + +import com.google.gson.stream.JsonReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory; +import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier; +import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; + +public class DomParser { + + /** + * Parsing JSON file into {@link NormalizedNode}. + * + * @param path path to the file + * @param schemaContext schema context + * @return created {@link NormalizedNode} + */ + public static NormalizedNode parseJsonFile(final String path, final EffectiveModelContext schemaContext) { + final JSONCodecFactory codecFactory = JSONCodecFactorySupplier.RFC7951.createSimple(schemaContext); + final NormalizedNodeResult resultHolder = new NormalizedNodeResult(); + try (NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder); + JsonParserStream jsonParser = JsonParserStream.create(writer, codecFactory, schemaContext); + InputStream inputStream = NetconfDomAccessorImpl.class.getResourceAsStream(path); + JsonReader reader = new JsonReader(new InputStreamReader(inputStream))) { + jsonParser.parse(reader); + } catch (IOException e) { + throw new IllegalStateException("Failed to parse input JSON file: " + path, e); + } + return resultHolder.getResult(); + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/NetconfDomAccessorImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/NetconfDomAccessorImpl.java new file mode 100644 index 000000000..4eaec246e --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/dom/NetconfDomAccessorImpl.java @@ -0,0 +1,161 @@ +/* + * ============LICENSE_START======================================================= + * ONAP : ccsdk features + * ================================================================================ + * Copyright (C) 2020 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.access.dom; + +import com.google.common.util.concurrent.FluentFuture; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfDomAccessor; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.NetconfAccessorImpl; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +//import org.opendaylight.mdsal.binding.dom.codec.impl.BindingCodecContext; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; +import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; +import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMNotificationListener; +import org.opendaylight.mdsal.dom.api.DOMNotificationService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfDomAccessorImpl extends NetconfAccessorImpl implements NetconfDomAccessor { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfDomAccessorImpl.class); + + private final DOMDataBroker dataBroker; + private final DOMMountPoint mountpoint; + private final DomContext domContext; + + public NetconfDomAccessorImpl(NetconfAccessorImpl accessor, DOMDataBroker domDataBroker, DOMMountPoint mountPoint, + DomContext domContext) { + super(accessor); + this.dataBroker = Objects.requireNonNull(domDataBroker); + this.mountpoint = Objects.requireNonNull(mountPoint); + this.domContext = Objects.requireNonNull(domContext); + } + + @Override + public DOMDataBroker getDataBroker() { + return dataBroker; + } + + @Override + public DOMMountPoint getMountpoint() { + return mountpoint; + } + + @Override + public @NonNull ListenerRegistration doRegisterNotificationListener( + @NonNull T listener, Collection types) { + LOG.info("Begin register listener for Mountpoint {}", mountpoint.getIdentifier().toString()); + final Optional optionalNotificationService = + mountpoint.getService(DOMNotificationService.class); + if (optionalNotificationService.isPresent()) { + final ListenerRegistration ranListenerRegistration = + optionalNotificationService.get().registerNotificationListener(listener, types); + LOG.info("End registration listener for Mountpoint {} Listener: {} Result: {}", + mountpoint.getIdentifier().toString(), optionalNotificationService, ranListenerRegistration); + return ranListenerRegistration; + } + throw new IllegalArgumentException("Can not get notification service"); + } + + @Override + public @NonNull ListenerRegistration doRegisterNotificationListener( + @NonNull T listener, SchemaPath[] types) { + return doRegisterNotificationListener(listener, Arrays.asList(types)); + } + + @Override + public Optional readData(LogicalDatastoreType dataStoreType, YangInstanceIdentifier path, + Class clazz) { + LOG.debug("Read to object datastore:{} path:{}", dataStoreType, path); + + try { + return convertNormalizedNode(domContext.getBindingNormalizedNodeSerializer(), + readDataNode(dataStoreType, path), path, clazz); + } catch (CanNotConvertException e) { + LOG.info("Incomplete read to class transaction {} {}", dataStoreType, path, e); + return Optional.empty(); + } + } + + @Override + public Optional> readDataNode(LogicalDatastoreType dataStoreType, + YangInstanceIdentifier path) { + LOG.debug("Read to node datastore:{} path:{}", dataStoreType, path); + + try (DOMDataTreeReadTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction()) { + FluentFuture>> foData = readOnlyTransaction.read(dataStoreType, path); + // RAVI - Add a few debug here, like what ? Speak to Micha.... + + Optional> data = foData.get(120, TimeUnit.SECONDS); + LOG.info("read is done - {} ", foData.isDone()); + return data; + + } catch (InterruptedException | ExecutionException | TimeoutException e) { + LOG.info("Incomplete read to node transaction {} {}", dataStoreType, path, e); + return Optional.empty(); + } + } + + @SuppressWarnings("unchecked") + private static Optional convertNormalizedNode(BindingNormalizedNodeSerializer serializer, + Optional> oData, YangInstanceIdentifier path, Class clazz) + throws CanNotConvertException { + if (oData.isPresent()) { + NormalizedNode data = oData.get(); + LOG.debug("data identifier: {}", data.getIdentifier()); + @Nullable + Entry, DataObject> entry = serializer.fromNormalizedNode(path, data); + if (entry != null) { + LOG.debug("object identifier: {}", entry.getKey()); + DataObject value = entry.getValue(); + if (clazz.isInstance(value)) { + return Optional.of((T) value); + } else { + throw new CanNotConvertException("Unexpected class. Expected:" + clazz.getName() + " provided:" + + value.getClass().getName() + " Nodetype:" + data.getNodeType()); + } + } else { + throw new CanNotConvertException( + "No object created for path:" + path + " Nodetype:" + data.getNodeType()); + } + } else { + throw new CanNotConvertException("No data received for path:" + path); + } + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java index 117e0892f..af095372d 100644 --- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java @@ -21,28 +21,14 @@ */ package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf; -/** - * @author Michael Dürre - * - */ - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import org.onap.ccsdk.features.sdnr.wt.common.configuration.Configuration; import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation; -import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener; -import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; -import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo.Protocol; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.IEsConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NetconfStateConfig implements Configuration { + @SuppressWarnings("unused") private static final Logger LOG = LoggerFactory.getLogger(NetconfStateConfig.class); public static final String SECTION_MARKER_NCSTATE = "netconfstate"; @@ -74,7 +60,7 @@ public class NetconfStateConfig implements Configuration { @Override public synchronized void defaults() { - // Add default if not available + // Add default if not available configuration.setPropertyIfNotAvailable(SECTION_MARKER_NCSTATE, PROPERTY_KEY_HANDLEASYNC, DEFAULT_VALUE_TRUSTALLCERTS); diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/resources/example.json b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/example.json new file mode 100644 index 000000000..e37eb8d6f --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/example.json @@ -0,0 +1,16 @@ +{ + "config:configuration": { + "config1": "test", + "config2": true, + "entry": [ + { + "setting": "set1", + "value": 1 + }, + { + "setting": "set1", + "value": 2 + } + ] + } +} \ No newline at end of file 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 index 72147364f..fbf36e5a0 100644 --- 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 @@ -26,35 +26,43 @@ - + + interface="org.opendaylight.mdsal.binding.api.NotificationPublishService"/> + interface="org.opendaylight.mdsal.binding.api.MountPointService"/> + + + interface="org.opendaylight.mdsal.binding.api.RpcProviderService"/> + + + + + + + +