diff options
author | Ravi Pendurty <ravi.pendurty@highstreet-technologies.com> | 2021-02-03 14:43:58 +0100 |
---|---|---|
committer | Dan Timoney <dtimoney@att.com> | 2021-02-05 22:56:21 +0000 |
commit | f7cc6a1daa39f583494dc0a71b89e1a1317a0a2b (patch) | |
tree | 6f780ecb8c6fc7be8ec2b3ab3f6baec1481be4c5 | |
parent | 8bbecead253c30da60577ecd014d59983e4b6113 (diff) |
Migrate websocketmanager and netconfnode-state-service
Migrate websocketmanager and netconfnode-state-service to Aluminium
Issue-ID: CCSDK-3131
Signed-off-by: Ravi Pendurty <ravi.pendurty@highstreet-technologies.com>
Change-Id: If82aa071b8187f6cbd02f187d93b61a15463d718
Signed-off-by: Ravi Pendurty <ravi.pendurty@highstreet-technologies.com>
36 files changed, 1445 insertions, 481 deletions
diff --git a/sdnr/wt/netconfnode-state-service/feature/pom.xml b/sdnr/wt/netconfnode-state-service/feature/pom.xml index 73311b18e..b7b6304c0 100644 --- a/sdnr/wt/netconfnode-state-service/feature/pom.xml +++ b/sdnr/wt/netconfnode-state-service/feature/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>single-feature-parent</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/netconfnode-state-service/installer/pom.xml b/sdnr/wt/netconfnode-state-service/installer/pom.xml index 297cd4595..b4b36984d 100755 --- a/sdnr/wt/netconfnode-state-service/installer/pom.xml +++ b/sdnr/wt/netconfnode-state-service/installer/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>odlparent-lite</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/netconfnode-state-service/model/pom.xml b/sdnr/wt/netconfnode-state-service/model/pom.xml index c731caee4..35501f6ec 100644 --- a/sdnr/wt/netconfnode-state-service/model/pom.xml +++ b/sdnr/wt/netconfnode-state-service/model/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>binding-parent</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfAccessor.java b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfAccessor.java index cca71457e..f24503957 100644 --- a/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfAccessor.java +++ b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfAccessor.java @@ -17,18 +17,9 @@ */ package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice; -import com.google.common.util.concurrent.ListenableFuture; -import java.util.List; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.mdsal.binding.api.DataBroker; -import org.opendaylight.mdsal.binding.api.MountPoint; -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.netmod.notification.rev080714.netconf.streams.Stream; +import java.util.Optional; 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.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.NotificationListener; -import org.opendaylight.yangtools.yang.common.RpcResult; /** * Interface handling netconf connection. @@ -52,62 +43,8 @@ public interface NetconfAccessor { */ Capabilities getCapabilites(); - /** - * @return the dataBroker - */ - DataBroker getDataBroker(); - - /** - * @return the MDSAL Mountpoint service - **/ - MountPoint getMountpoint(); - - /** - * @Return TransAction - */ - TransactionUtils getTransactionUtils(); - - /** - * Register netconf notification listener for related mountpoint - * - * @param <T> specific child class of NotificationListener - * @param listener listener to be called - * @return handler to manager registration - */ - <T extends NotificationListener> ListenerRegistration<NotificationListener> doRegisterNotificationListener( - @NonNull T listener); + Optional<NetconfBindingAccessor> getNetconfBindingAccessor(); - /** - * Register notifications stream for the connection. - * - * @param streamName that should be "NETCONF" as default. - * @return progress indication - */ - ListenableFuture<RpcResult<CreateSubscriptionOutput>> registerNotificationsStream(String streamName); - - /** - * Register notifications stream for the connection - * - * @param streamList that contains a list of streams to be subscribed for notifications - * @return progress indication - */ - void registerNotificationsStream(List<Stream> streamList); - - /** - * check if the device supports notifications.yang - * @return true if notifications.yang is supported - */ -// boolean isNotificationsSupported(); - - /** - * check if the device supports notifications.yang - * @return true if nc-notifications.yang is supported - */ - boolean isNCNotificationsSupported(); - /** - * Get all notification streams - * @return stream list - */ - List<Stream> getNotificationStreams(); + Optional<NetconfDomAccessor> getNetconfDomAccessor(); } diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfBindingAccessor.java b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfBindingAccessor.java new file mode 100644 index 000000000..ffcacf213 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfBindingAccessor.java @@ -0,0 +1,64 @@ +/* + * ============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; + +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.MountPoint; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.NotificationListener; + +/** + * Interface handling netconf connection. + */ +public interface NetconfBindingAccessor extends NetconfAccessor { + + /** + * @return the dataBroker + */ + DataBroker getDataBroker(); + + /** + * @return the MDSAL Mountpoint service + **/ + MountPoint getMountpoint(); + + /** + * Get handler for read/write + * @Return Transaction + */ + TransactionUtils getTransactionUtils(); + + /** + * Get notifications handler + * @return + */ + Optional<NetconfNotifications> getNotificationAccessor(); + + /** + * Register netconf notification listener for related mountpoint + * + * @param <T> specific child class of NotificationListener + * @param listener listener to be called + * @return handler to manager registration + */ + <T extends NotificationListener> ListenerRegistration<NotificationListener> doRegisterNotificationListener( + @NonNull T listener); + +} diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfDomAccessor.java b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfDomAccessor.java new file mode 100644 index 000000000..0818f7972 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfDomAccessor.java @@ -0,0 +1,89 @@ +/* + * ============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; + +import java.util.Collection; +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; +import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMNotificationListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +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; + +/** + * Interface handling netconf connection. + */ +public interface NetconfDomAccessor extends NetconfAccessor { + + /** + * @return the dataBroker + */ + DOMDataBroker getDataBroker(); + + /** + * @return the MDSAL Mountpoint service + **/ + DOMMountPoint getMountpoint(); + + /** + * Deliver the data into a class + * @param <T> DataObject type + * @param dataStoreType config or operational database + * @param path data path + * @return Optional<T> with object + */ + <T extends DataObject> Optional<T> readData(LogicalDatastoreType dataStoreType, YangInstanceIdentifier path, + Class<T> clazz); + + /** + * Read data from device + * @param dataStoreType + * @param path + * @return NormalizedNode<?, ?> with data + */ + Optional<NormalizedNode<?, ?>> readDataNode(LogicalDatastoreType dataStoreType, YangInstanceIdentifier path); + + /** + * Register netconf notification listener for related mountpoint + * + * @param <T> specific child class of DOMNotificationListener + * @param listener listener to be called + * @param types + * @return handler to manager registration + */ + <T extends DOMNotificationListener> @NonNull ListenerRegistration<DOMNotificationListener> doRegisterNotificationListener( + @NonNull T listener, Collection<SchemaPath> types); + /** + * Register netconf notification listener for related mountpoint + * + * @param <T> + * @param listener + * @param types + * @return + */ + <T extends DOMNotificationListener> @NonNull ListenerRegistration<DOMNotificationListener> doRegisterNotificationListener( + @NonNull T listener, SchemaPath[] types); + + + +} diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfNotifications.java b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfNotifications.java new file mode 100644 index 000000000..b13030dee --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/NetconfNotifications.java @@ -0,0 +1,66 @@ +/* + * ============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; + +import com.google.common.util.concurrent.ListenableFuture; +import java.util.List; +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.netmod.notification.rev080714.netconf.streams.Stream; +import org.opendaylight.yangtools.yang.common.RpcResult; + +/** + * Interface handling netconf connection. + */ +public interface NetconfNotifications { + + static String DefaultNotificationsStream = "NETCONF"; + + /** + * check if the device supports notifications.yang + * @return true if notifications.yang is supported + */ + boolean isNotificationsSupported(); + + /** + * check if the device supports notifications.yang + * @return true if nc-notifications.yang is supported + */ + boolean isNCNotificationsSupported(); + /** + * Get all notification streams + * @return stream list + */ + List<Stream> getNotificationStreams(); + + /** + * Register notifications stream for the connection + * + * @param streamList that contains a list of streams to be subscribed for notifications + * @return progress indication + */ + void registerNotificationsStream(List<Stream> streamList); + + /** + * Register notifications stream for the connection. + * + * @param streamName that should be "NETCONF" as default. + * @return progress indication + */ + ListenableFuture<RpcResult<CreateSubscriptionOutput>> registerNotificationsStream(String streamName); + +} diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/yang/config.yang b/sdnr/wt/netconfnode-state-service/model/src/main/yang/config.yang new file mode 100644 index 000000000..82886e63b --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/model/src/main/yang/config.yang @@ -0,0 +1,29 @@ +module config { + yang-version 1.1; + namespace urn:ietf:params:xml:ns:yang:config; + prefix config; + + revision 2020-12-08 { + description "Initial revision"; + } + + container configuration { + list entry { + key "setting"; + + leaf setting { + type string; + } + leaf value { + type uint8; + } + } + + leaf config1 { + type string; + } + leaf config2 { + type boolean; + } + } +}
\ No newline at end of file diff --git a/sdnr/wt/netconfnode-state-service/pom.xml b/sdnr/wt/netconfnode-state-service/pom.xml index 20c21c822..793fa73fc 100755 --- a/sdnr/wt/netconfnode-state-service/pom.xml +++ b/sdnr/wt/netconfnode-state-service/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>odlparent-lite</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/netconfnode-state-service/provider/pom.xml b/sdnr/wt/netconfnode-state-service/provider/pom.xml index 2b428e0be..2d90e38cc 100644 --- a/sdnr/wt/netconfnode-state-service/provider/pom.xml +++ b/sdnr/wt/netconfnode-state-service/provider/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>binding-parent</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> @@ -47,7 +47,6 @@ </licenses> <properties> - <checkstyle.skip>true</checkstyle.skip> <!-- POM configuration --> <maven.javadoc.skip>true</maven.javadoc.skip> <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format> <buildtime>${maven.build.timestamp} UTC</buildtime> @@ -55,8 +54,34 @@ <dependencies> <dependency> - <groupId>org.opendaylight.netconf</groupId> - <artifactId>sal-netconf-connector</artifactId> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + <!-- md-sal --> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-binding-dom-codec-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-binding-dom-adapter</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-binding-generator-impl</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-binding-runtime-spi</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-dom-api</artifactId> <scope>provided</scope> </dependency> <dependency> @@ -64,16 +89,29 @@ <artifactId>mdsal-singleton-common-api</artifactId> <scope>provided</scope> </dependency> + <!-- md-sal --> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>netconf-dom-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>sal-netconf-connector</artifactId> + <scope>provided</scope> + </dependency> + <!-- akka --> <dependency> <groupId>com.typesafe.akka</groupId> - <artifactId>akka-actor_2.12</artifactId> + <artifactId>akka-actor_2.13</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> - <artifactId>akka-cluster_2.12</artifactId> + <artifactId>akka-cluster_2.13</artifactId> <scope>provided</scope> </dependency> + <!-- wt --> <dependency> <groupId>${project.groupId}</groupId> <artifactId>sdnr-wt-common</artifactId> 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<Topology> 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 <T extends NotificationListener> ListenerRegistration<NotificationListener> doRegisterNotificationListener( - @NonNull T listener) { - log.info("Begin register listener for Mountpoint {}", mountpoint.getIdentifier().toString()); - final Optional<NotificationService> optionalNotificationService = - mountpoint.getService(NotificationService.class); - final NotificationService notificationService = optionalNotificationService.get(); - final ListenerRegistration<NotificationListener> ranListenerRegistration = - notificationService.registerNotificationListener(listener); - log.info("End registration listener for Mountpoint {} Listener: {} Result: {}", - mountpoint.getIdentifier().toString(), optionalNotificationService, ranListenerRegistration); - return ranListenerRegistration; - } - - @Override - public ListenableFuture<RpcResult<CreateSubscriptionOutput>> registerNotificationsStream(String streamName) { - - String failMessage = ""; - final Optional<RpcConsumerRegistry> 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<CreateSubscriptionOutput> result = RpcResultBuilder.failed(); - result.withError(ErrorType.APPLICATION, failMessage); - SettableFuture<RpcResult<CreateSubscriptionOutput>> res = SettableFuture.create(); - res.set(result.build()); - return res; - } - - @Override - public void registerNotificationsStream(List<Stream> 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<Stream> getNotificationStreams() { - final Class<Netconf> netconfClazz = Netconf.class; - InstanceIdentifier<Netconf> 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<String, NetconfAccessorImpl> 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<Topology> NETCONF_TOPO_IID = InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); - @SuppressWarnings("null") private static final @NonNull 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 = + private static final @NonNull DataTreeIdentifier<Node> 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<L1> 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<NetconfNodeConnectListener> 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<Node> instanceIdentifier = - NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName))); - - Optional<MountPoint> 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<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(); - 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<NetconfBindingAccessor> getNetconfBindingAccessor() { + return netconfCommunicatorManager.getNetconfBindingAccessor(this); + } + + @Override + public Optional<NetconfDomAccessor> 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<Topology> NETCONF_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, + new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); + + private final ConcurrentHashMap<NodeId, NetconfAccessor> 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<Topology> NETCONF_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, + new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); + + private static final @NonNull InstanceIdentifier<Node> 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<NetconfBindingAccessor> getNetconfBindingAccessor(NetconfAccessorImpl accessor) { + String mountPointNodeName = accessor.getNodeId().getValue(); + InstanceIdentifier<Node> instanceIdentifier = + NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName))); + + final Optional<MountPoint> 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<DataBroker> 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<NetconfDomAccessor> 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<DOMMountPoint> mountPoint = domMountPointService.getMountPoint(mountpointPath); + if (mountPoint.isEmpty()) { + return Optional.empty(); + } + + final Optional<DOMDataBroker> 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/GenericTransactionUtils.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/access/binding/GenericTransactionUtils.java index 755224027..282048453 100644 --- 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/access/binding/GenericTransactionUtils.java @@ -15,7 +15,7 @@ * the License. * ============LICENSE_END========================================================================== */ -package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl; +package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.binding; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.FluentFuture; @@ -25,7 +25,6 @@ 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; @@ -80,7 +79,6 @@ public final class GenericTransactionUtils implements TransactionUtils { * @return null or object */ @Override - @SuppressWarnings("null") public @Nullable <T extends DataObject> T readDataOptionalWithStatus(DataBroker dataBroker, LogicalDatastoreType dataStoreType, InstanceIdentifier<T> iid, AtomicBoolean noErrorIndication, AtomicReference<String> statusIndicator) { 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 <T extends NotificationListener> ListenerRegistration<NotificationListener> doRegisterNotificationListener( + @NonNull T listener) { + log.info("Begin register listener for Mountpoint {}", mountpoint.getIdentifier().toString()); + final Optional<NotificationService> optionalNotificationService = + mountpoint.getService(NotificationService.class); + final NotificationService notificationService = optionalNotificationService.get(); + final ListenerRegistration<NotificationListener> 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<RpcResult<CreateSubscriptionOutput>> registerNotificationsStream(@NonNull String streamName) { + String failMessage = ""; + final Optional<RpcConsumerRegistry> 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<CreateSubscriptionOutput> result = RpcResultBuilder.failed(); + result.withError(ErrorType.APPLICATION, failMessage); + SettableFuture<RpcResult<CreateSubscriptionOutput>> future = SettableFuture.create(); + future.set(result.build()); + return future; + } + + @Override + public void registerNotificationsStream(List<Stream> 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<Stream> getNotificationStreams() { + final Class<Netconf> netconfClazz = Netconf.class; + InstanceIdentifier<Netconf> 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<NetconfNotifications> 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 <T extends DOMNotificationListener> ListenerRegistration<DOMNotificationListener> doRegisterNotificationListener( + @NonNull T listener, Collection<SchemaPath> types) { + LOG.info("Begin register listener for Mountpoint {}", mountpoint.getIdentifier().toString()); + final Optional<DOMNotificationService> optionalNotificationService = + mountpoint.getService(DOMNotificationService.class); + if (optionalNotificationService.isPresent()) { + final ListenerRegistration<DOMNotificationListener> 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 <T extends DOMNotificationListener> ListenerRegistration<DOMNotificationListener> doRegisterNotificationListener( + @NonNull T listener, SchemaPath[] types) { + return doRegisterNotificationListener(listener, Arrays.asList(types)); + } + + @Override + public <T extends DataObject> Optional<T> readData(LogicalDatastoreType dataStoreType, YangInstanceIdentifier path, + Class<T> 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<NormalizedNode<?, ?>> readDataNode(LogicalDatastoreType dataStoreType, + YangInstanceIdentifier path) { + LOG.debug("Read to node datastore:{} path:{}", dataStoreType, path); + + try (DOMDataTreeReadTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction()) { + FluentFuture<Optional<NormalizedNode<?, ?>>> foData = readOnlyTransaction.read(dataStoreType, path); + // RAVI - Add a few debug here, like what ? Speak to Micha.... + + Optional<NormalizedNode<?, ?>> 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 <T extends DataObject> Optional<T> convertNormalizedNode(BindingNormalizedNodeSerializer serializer, + Optional<NormalizedNode<?, ?>> oData, YangInstanceIdentifier path, Class<T> clazz) + throws CanNotConvertException { + if (oData.isPresent()) { + NormalizedNode<?, ?> data = oData.get(); + LOG.debug("data identifier: {}", data.getIdentifier()); + @Nullable + Entry<InstanceIdentifier<?>, 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 @@ <blueprint xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" xmlns="http://www.osgi.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="dataBroker" interface="org.opendaylight.mdsal.binding.api.DataBroker"/> <reference id="notificationPublishService" - interface="org.opendaylight.mdsal.binding.api.NotificationPublishService" - odl:type="default"/> + interface="org.opendaylight.mdsal.binding.api.NotificationPublishService"/> <reference id="mountPointService" - interface="org.opendaylight.mdsal.binding.api.MountPointService" - odl:type="default"/> + interface="org.opendaylight.mdsal.binding.api.MountPointService"/> + + <reference id="domMountPointService" + interface="org.opendaylight.mdsal.dom.api.DOMMountPointService"/> <reference id="rpcProviderRegistry" - interface="org.opendaylight.mdsal.binding.api.RpcProviderService" - odl:type="default"/> + interface="org.opendaylight.mdsal.binding.api.RpcProviderService"/> <reference id="clusterSingletonService" interface="org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider"/> <reference id="iEntityDataProvider" - availability="mandatory" activation="eager" interface="org.onap.ccsdk.features.sdnr.wt.dataprovider.model.IEntityDataProvider"/> + <reference id="yangParserFactory" + interface="org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory"/> + + <reference id="bindingNormalizedNodeSerializer" + interface="org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer"/> + + <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="domMountPointService" ref="domMountPointService"/> <property name="clusterSingletonService" ref="clusterSingletonService"/> <property name="entityDataProvider" ref="iEntityDataProvider"/> + <property name="yangParserFactory" ref="yangParserFactory"/> + <property name="bindingNormalizedNodeSerializer" ref="bindingNormalizedNodeSerializer"/> </bean> <service id="registerNetconfNodeStateService" diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/resources/sample.json b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/sample.json new file mode 100644 index 000000000..b1f3e14e8 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/sample.json @@ -0,0 +1,20 @@ +{ + "config:configuration": { + "config1": "this is a test", + "entry": [ + { + "setting": "setting-3", + "value": 255 + }, + { + "setting": "setting-1", + "value": 1 + }, + { + "setting": "setting-2", + "value": 2 + } + ], + "config2": true + } +}
\ No newline at end of file diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestDom.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestDom.java new file mode 100644 index 000000000..f7aef6b6d --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestDom.java @@ -0,0 +1,80 @@ +/* + * ============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.test; + +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.io.StringWriter; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SeverityType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.FaultNotification; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.FaultNotificationBuilder; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter; +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.JSONNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestDom { + + private static final Logger LOG = LoggerFactory.getLogger(TestDom.class); + + @Test + public void test2() { + FaultNotification faultNotification = + new FaultNotificationBuilder().setCounter(1).setNodeId("Node1").setSeverity(SeverityType.Major).build(); + +// final NormalizedNode<?, ?> data = DomContext.getBINDING_CONTEXT() +// .toNormalizedNode(InstanceIdentifier.create(FaultNotification.class), faultNotification).getValue(); + +// LOG.info("Normalized node: {}", data); +// final String json = toJson(data, schemaContext); +// LOG.info(json); + + } + /** + * Serialization of {@link NormalizedNode} into {@link String}. + * + * @param node to be serialized data + * @param schemaContext schema context + * @return serialized data + */ + private static String toJson(final NormalizedNode<?, ?> node, final EffectiveModelContext schemaContext) { + final JSONCodecFactory codecFactory = JSONCodecFactorySupplier.RFC7951.createSimple(schemaContext); + try (StringWriter stringWriter = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(stringWriter); + NormalizedNodeWriter nodeStreamer = NormalizedNodeWriter.forStreamWriter( + JSONNormalizedNodeStreamWriter.createNestedWriter(codecFactory, SchemaPath.ROOT, + schemaContext.getQName().getNamespace(), jsonWriter))) { + jsonWriter.beginObject(); + nodeStreamer.write(node); + jsonWriter.endObject(); + return stringWriter.toString(); + } catch (IOException e) { + throw new IllegalStateException("Failed to convert input node to JSON: " + node, e); + } + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java index ad410dd44..5de8b7075 100644 --- a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java +++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java @@ -44,25 +44,26 @@ import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnectListener; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateListener; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.GenericTransactionUtils; -import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.NetconfAccessorImpl; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.NetconfNodeStateServiceImpl; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.NetconfnodeStateServiceRpcApiImpl; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.example.ExampleConfig; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.ClusterSingletonServiceProviderMock; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.MountPointMock; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.MountPointServiceMock; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.NotificationPublishServiceMock; import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.test.mock.RpcProviderRegistryMock; +import org.opendaylight.binding.runtime.spi.BindingRuntimeHelpers; 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.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.binding.dom.codec.impl.BindingCodecContext; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder; @@ -86,6 +87,9 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.parser.impl.YangParserFactoryImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,6 +109,7 @@ public class TestNetconfNodeStateService extends Mockito { private static final Logger LOG = LoggerFactory.getLogger(TestNetconfNodeStateService.class); + @SuppressWarnings("unchecked") @BeforeClass public static <T extends DataObject, L extends DataTreeChangeListener<T>> void before() throws InterruptedException, IOException { @@ -120,8 +125,6 @@ public class TestNetconfNodeStateService extends Mockito { //dataBrokerNetconf = new DataBrokerNetconfMock(); //dataBrokerNetconf.newReadWriteTransaction(); dataBrokerNetconf = mock(DataBroker.class); - ArgumentCaptor<DataTreeIdentifier<?>> argument1 = ArgumentCaptor.forClass(DataTreeIdentifier.class); - ArgumentCaptor<DataTreeChangeListener<?>> argument2 = ArgumentCaptor.forClass(DataTreeChangeListener.class); when(dataBrokerNetconf.registerDataTreeChangeListener(any(), any())).thenAnswer( invocation -> { Object pListener = invocation.getArguments()[1]; @@ -153,7 +156,8 @@ public class TestNetconfNodeStateService extends Mockito { NotificationPublishService notificationPublishService = new NotificationPublishServiceMock(); RpcProviderService rpcProviderRegistry = new RpcProviderRegistryMock(); IEntityDataProvider entityProviderMock = mock(IEntityDataProvider.class); - + YangParserFactory yangParserFactory = new YangParserFactoryImpl(); + BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer = new BindingCodecContext(BindingRuntimeHelpers.createRuntimeContext()); // start using blueprint interface netconfStateService = new NetconfNodeStateServiceImpl(); @@ -163,6 +167,8 @@ public class TestNetconfNodeStateService extends Mockito { netconfStateService.setRpcProviderRegistry(rpcProviderRegistry); netconfStateService.setClusterSingletonService(clusterSingletonService); netconfStateService.setEntityDataProvider(entityProviderMock); + netconfStateService.setYangParserFactory(yangParserFactory); + netconfStateService.setBindingNormalizedNodeSerializer(bindingNormalizedNodeSerializer); netconfStateService.init(); System.out.println("Initialization done"); } @@ -233,11 +239,10 @@ public class TestNetconfNodeStateService extends Mockito { String nodeIdString = "Test"; NodeId nodeId = new NodeId(nodeIdString); NodeBuilder nodeBuilder = new NodeBuilder(); - nodeBuilder.addAugmentation(NetconfNode.class, rootNodeNetconf); + + nodeBuilder.addAugmentation(rootNodeNetconf); nodeBuilder.setNodeId(nodeId); Node rootNode = nodeBuilder.build(); - NetconfAccessor acessor = new NetconfAccessorImpl(nodeId, rootNodeNetconf, mountPoint.getDataBroker(), - mountPoint, new GenericTransactionUtils()); DataObjectModification<Node> dom = mock(DataObjectModification.class); when(dom.getDataAfter()).thenReturn(rootNode); @@ -271,7 +276,7 @@ public class TestNetconfNodeStateService extends Mockito { NetconfNode rootNodeNetconf = netconfNodeBuilder.build(); NodeBuilder nodeBuilder = new NodeBuilder(); - nodeBuilder.addAugmentation(NetconfNode.class, rootNodeNetconf); + nodeBuilder.addAugmentation(rootNodeNetconf); nodeBuilder.setNodeId(new NodeId("Test")); Node rootNodeAfter = nodeBuilder.build(); @@ -351,6 +356,10 @@ public class TestNetconfNodeStateService extends Mockito { System.out.println("Output " + output); } + @Test + public void test10ApiPushNotifiction() throws YangParserException, IOException { + ExampleConfig.exampleConfig(netconfStateService.getDomContext()); + } // ------- private section diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/example/ExampleConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/example/ExampleConfig.java new file mode 100644 index 000000000..f17453803 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/example/ExampleConfig.java @@ -0,0 +1,77 @@ +/* + * ============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.test.example; + +import java.io.IOException; +import java.net.URI; +import java.util.Objects; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.DomContext; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.access.dom.DomParser; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.config.rev201208.Configuration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.parser.api.YangParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExampleConfig { + + private static final Logger LOG = LoggerFactory.getLogger(ExampleConfig.class); + + // specification of YANG module + private static final QNameModule CONFIG_MODULE = QNameModule.create( + URI.create("urn:ietf:params:xml:ns:yang:config"), Revision.of("2020-12-08")); + // path to 'configuration' container (it is a root container) + private static final YangInstanceIdentifier CONFIGURATION_PATH = YangInstanceIdentifier.builder() + .node(QName.create(CONFIG_MODULE, "configuration")) + .build(); + + + public static void exampleConfig(DomContext domContext) throws YangParserException, IOException { + // (1) preparation of schema context with module that describes configuration (it is possible to load multiple + // schemas into parser) + //final YangParser parser = new YangParserFactoryImpl().createParser(); + final YangParser parser = domContext.getYangParserFactory().createParser(); + parser.addSource(YangTextSchemaSource.forResource("/META-INF/yang/config@2020-12-08.yang")); + final EffectiveModelContext schemaContext = parser.buildEffectiveModel(); + + // (2) parsing of configuration into binding-independent format + final NormalizedNode<?, ?> data = DomParser.parseJsonFile("/example.json", schemaContext); + + // (3) conversion into binding-aware format (md-sal codec needs to know about path on which data is placed) + final Configuration config = (Configuration) domContext.getBindingNormalizedNodeSerializer().fromNormalizedNode(CONFIGURATION_PATH, data) + .getValue(); + + // (4) printing some useful information + LOG.info("Value of 'config1': {}", config.getConfig1()); + LOG.info("Value of 'config2': {}", config.isConfig2()); + Objects.requireNonNull(config.getEntry()).forEach((entryKey, entry) -> + LOG.info("Value of '{}' setting: {}", entry.getSetting(), entry.getValue())); + } + +} diff --git a/sdnr/wt/websocketmanager2/feature/pom.xml b/sdnr/wt/websocketmanager2/feature/pom.xml index 2a44166fa..f3f6d25bf 100644 --- a/sdnr/wt/websocketmanager2/feature/pom.xml +++ b/sdnr/wt/websocketmanager2/feature/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>single-feature-parent</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/websocketmanager2/installer/pom.xml b/sdnr/wt/websocketmanager2/installer/pom.xml index 5e87f76a5..418329b07 100755 --- a/sdnr/wt/websocketmanager2/installer/pom.xml +++ b/sdnr/wt/websocketmanager2/installer/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>odlparent-lite</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/websocketmanager2/model/pom.xml b/sdnr/wt/websocketmanager2/model/pom.xml index 30175678a..129396229 100644 --- a/sdnr/wt/websocketmanager2/model/pom.xml +++ b/sdnr/wt/websocketmanager2/model/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>binding-parent</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> @@ -39,4 +39,8 @@ <packaging>bundle</packaging> <name>ccsdk-features :: ${project.artifactId}</name> + + <properties> + <maven.javadoc.skip>true</maven.javadoc.skip> + </properties> </project> diff --git a/sdnr/wt/websocketmanager2/pom.xml b/sdnr/wt/websocketmanager2/pom.xml index f00295fac..22ab15815 100755 --- a/sdnr/wt/websocketmanager2/pom.xml +++ b/sdnr/wt/websocketmanager2/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>odlparent-lite</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> diff --git a/sdnr/wt/websocketmanager2/provider/pom.xml b/sdnr/wt/websocketmanager2/provider/pom.xml index 537d69581..63dd0b559 100644 --- a/sdnr/wt/websocketmanager2/provider/pom.xml +++ b/sdnr/wt/websocketmanager2/provider/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.ccsdk.parent</groupId> <artifactId>binding-parent</artifactId> - <version>2.1.0</version> + <version>2.1.1-SNAPSHOT</version> <relativePath/> </parent> @@ -48,7 +48,6 @@ <properties> <maven.javadoc.skip>true</maven.javadoc.skip> - <checkstyle.skip>true</checkstyle.skip> </properties> <dependencies> @@ -59,7 +58,7 @@ </dependency> <dependency> <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> + <artifactId>javax.servlet-api</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty.websocket</groupId> @@ -84,11 +83,11 @@ </dependency> <dependency> <groupId>com.typesafe.akka</groupId> - <artifactId>akka-actor_2.12</artifactId> + <artifactId>akka-actor_2.13</artifactId> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> - <artifactId>akka-cluster_2.12</artifactId> + <artifactId>akka-cluster_2.13</artifactId> </dependency> <dependency> <groupId>org.java-websocket</groupId> @@ -100,8 +99,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.opendaylight.controller</groupId> - <artifactId>sal-binding-api</artifactId> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>mdsal-binding-api</artifactId> </dependency> <dependency> <groupId>org.osgi</groupId> @@ -122,17 +121,4 @@ <scope>test</scope> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <source>1.8</source> - <target>1.8</target> - </configuration> - </plugin> - </plugins> - </build> </project> diff --git a/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml index 9a0dd1d8c..d92738ada 100644 --- a/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml +++ b/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml @@ -27,7 +27,7 @@ xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" odl:use-default-for-reference-types="true"> - <reference id="rpcProviderRegistry" interface="org.opendaylight.mdsal.binding.api.RpcProviderService" odl:type="default"/> + <reference id="rpcProviderRegistry" interface="org.opendaylight.mdsal.binding.api.RpcProviderService"/> <bean id="provider" class="org.onap.ccsdk.features.sdnr.wt.websocketmanager2.WebSocketManagerProvider" init-method="init" destroy-method="close"> <property name="rpcProviderRegistry" ref="rpcProviderRegistry"/> |