summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actn-interface-tools/global-control/pom.xml31
-rw-r--r--actn-interface-tools/pom.xml24
-rw-r--r--actn-interface-tools/restconf-client/api/pom.xml45
-rw-r--r--actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/DefaultPncInstance.java127
-rw-r--r--actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/PncInstance.java81
-rw-r--r--actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestConfSBController.java216
-rw-r--r--actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestconfNotificationEventListener.java36
-rw-r--r--actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/WebClientUtil.java61
-rw-r--r--actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/package-info.java24
-rw-r--r--actn-interface-tools/restconf-client/ctl/pom.xml81
-rw-r--r--actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/RestConfSBControllerImpl.java512
-rw-r--r--actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/package-info.java24
-rw-r--r--actn-interface-tools/restconf-client/pom.xml89
-rw-r--r--actn-interface-tools/yang-utils/pom.xml30
14 files changed, 1381 insertions, 0 deletions
diff --git a/actn-interface-tools/global-control/pom.xml b/actn-interface-tools/global-control/pom.xml
new file mode 100644
index 0000000..1c01ad8
--- /dev/null
+++ b/actn-interface-tools/global-control/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ Actn Interface Tools
+ ~ ================================================================================
+ ~ Copyright (C) 2022 Huawei Canada Limited.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>actn-interface-tools</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>global-control</artifactId>
+</project>
+
diff --git a/actn-interface-tools/pom.xml b/actn-interface-tools/pom.xml
index baa2400..b92341b 100644
--- a/actn-interface-tools/pom.xml
+++ b/actn-interface-tools/pom.xml
@@ -31,10 +31,14 @@
<modules>
<module>actn-model</module>
<module>actn-client</module>
+ <module>global-control</module>
+ <module>yang-utils</module>
+ <module>restconf-client</module>
</modules>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
+ <slf4j.version>1.7.21</slf4j.version>
</properties>
<dependencies>
<dependency>
@@ -49,12 +53,32 @@
<version>2.0.1</version>
<scope>compile</scope>
</dependency>
+
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<scope>provided</scope>
<version>1.9.12</version>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service-annotations</artifactId>
+ <version>1.0</version>
+ <scope>compile</scope>
+ </dependency>
+
+
+
</dependencies>
</project> \ No newline at end of file
diff --git a/actn-interface-tools/restconf-client/api/pom.xml b/actn-interface-tools/restconf-client/api/pom.xml
new file mode 100644
index 0000000..49998cb
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ Actn Interface Tools
+ ~ ================================================================================
+ ~ Copyright (C) 2023 Huawei Canada Limited.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>restconf-client</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <!-- <packaging>bundle</packaging>-->
+ <packaging>jar</packaging>
+ <description>ONOS RESTCONF southbound plugin API</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.5</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/DefaultPncInstance.java b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/DefaultPncInstance.java
new file mode 100644
index 0000000..4bb8b66
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/DefaultPncInstance.java
@@ -0,0 +1,127 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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.integration.actninterfacetools.protocol.restconf;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.StringUtils;
+import java.net.InetAddress;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * Default implementation for Rest devices.
+ */
+public class DefaultPncInstance implements PncInstance {
+ private static final String REST = "rest";
+ private static final String COLON = ":";
+
+ private final UUID pncId;
+ private final InetAddress ip;
+ private final int port;
+ private final String username;
+ private final String password;
+ private String protocol;
+ private String url;
+
+ public DefaultPncInstance(InetAddress ip, int port, String name, String password,
+ String protocol, String url) {
+ this.pncId = UUID.randomUUID();
+ Preconditions.checkNotNull(ip, "IP address cannot be null");
+ Preconditions.checkArgument(port > 0, "Port address cannot be negative");
+ Preconditions.checkNotNull(protocol, "protocol address cannot be null");
+ this.ip = ip;
+ this.port = port;
+ this.username = name;
+ this.password = StringUtils.isEmpty(password) ? null : password;
+ this.protocol = protocol;
+ this.url = StringUtils.isEmpty(url) ? null : url;
+ }
+
+ @Override
+ public InetAddress ip() {
+ return this.ip;
+ }
+
+ @Override
+ public int port() {
+ return this.port;
+ }
+
+ @Override
+ public String username() {
+ return this.username;
+ }
+
+ @Override
+ public String password() {
+ return this.password;
+ }
+
+ @Override
+ public UUID pncId() {
+ return this.pncId;
+ }
+
+ @Override
+ public String protocol() {
+ return protocol;
+ }
+
+ @Override
+ public String url() {
+ return url;
+ }
+
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .omitNullValues()
+ .add("url", url)
+ .add("protocol", protocol)
+ .add("username", username)
+ .add("port", port)
+ .add("ip", ip)
+ .toString();
+
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof PncInstance)) {
+ return false;
+ }
+ PncInstance pncInstance = (PncInstance) obj;
+ return this.username.equals(pncInstance.username()) && this.ip.equals(pncInstance.ip()) &&
+ this.port == pncInstance.port();
+
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ip, port);
+ }
+
+}
diff --git a/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/PncInstance.java b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/PncInstance.java
new file mode 100644
index 0000000..a6726e8
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/PncInstance.java
@@ -0,0 +1,81 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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.integration.actninterfacetools.protocol.restconf;
+
+import java.net.InetAddress;
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * Represents an abstraction of a Pnc.
+ */
+public interface PncInstance {
+ /**
+ * Returns the ip of the Pnc Service.
+ *
+ * @return ip
+ */
+ InetAddress ip();
+
+ /**
+ * Returns the port of the Pnc Service.
+ *
+ * @return port
+ */
+ int port();
+
+ /**
+ * Returns the username of the Pnc Service.
+ *
+ * @return username
+ */
+ String username();
+
+ /**
+ * Returns the password of the Pnc Service.
+ *
+ * @return password
+ */
+ String password();
+
+ /**
+ * Returns the pncId.
+ *
+ * @return pncId
+ */
+ UUID pncId();
+
+
+ /**
+ * Returns the protocol for the REST request, usually HTTP o HTTPS.
+ *
+ * @return protocol
+ */
+ String protocol();
+
+ /**
+ * Returns the url for the REST requests, to be used instead of IP and PORT.
+ *
+ * @return url
+ */
+ String url();
+
+}
diff --git a/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestConfSBController.java b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestConfSBController.java
new file mode 100644
index 0000000..86cfbc6
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestConfSBController.java
@@ -0,0 +1,216 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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.integration.actninterfacetools.protocol.restconf;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import javax.ws.rs.core.MediaType;
+import java.net.InetAddress;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Abstraction of a RESTCONF controller. Serves as a one-stop shop for obtaining
+ * RESTCONF southbound devices and (un)register listeners.
+ */
+public interface RestConfSBController {
+ /**
+ * Returns all the devices known to this controller.
+ *
+ * @return map of devices
+ */
+ Map<UUID, PncInstance> getPncInstances();
+
+ /**
+ * Returns a device by node identifier.
+ *
+ * @param deviceInfo node identifier
+ * @return RestSBDevice rest device
+ */
+ PncInstance getPncInstance(UUID deviceInfo);
+
+ /**
+ * Returns a device by Ip and Port.
+ *
+ * @param ip device ip
+ * @param port device port
+ * @return RestSBDevice rest device
+ */
+ PncInstance getPncInstance(InetAddress ip, int port);
+
+ /**
+ * Adds a device to the device map.
+ *
+ * @param pncInstance to be added
+ */
+ void addPncInstance(PncInstance pncInstance);
+
+ /**
+ * Removes the device from the devices map.
+ *
+ * @param pncId to be removed
+ */
+ void removeDevice(UUID pncId);
+ /**
+ * This method is to be called by whoever is interested to receive
+ * Notifications from a specific device. It does a REST GET request
+ * with specified parameters to the device, and calls the provided
+ * callBackListener upon receiving notifications to notify the requester
+ * about notifications.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param mediaType format to retrieve the content in
+ * @param callBackListener method to call when notifications arrives
+ */
+ void enableNotifications(UUID pncId, String request, String mediaType,
+ RestconfNotificationEventListener callBackListener);
+
+ /**
+ * Registers a listener for notification events that occur to restconf
+ * devices.
+ *
+ * @param pncId identifier of the pnc to which the listener is attached
+ * @param listener the listener to notify
+ */
+ void addNotificationListener(UUID pncId,
+ RestconfNotificationEventListener listener);
+
+ /**
+ * Unregisters the listener for the device.
+ *
+ * @param pncId identifier of the pnc for which the listener
+ * is to be removed
+ * @param listener listener to be removed
+ */
+ void removeNotificationListener(UUID pncId,
+ RestconfNotificationEventListener listener);
+
+ /**
+ * Returns true if a listener has been installed to listen to RESTCONF
+ * notifications sent from a particular device.
+ *
+ * @param pncId identifier of the pnc from which the notifications
+ * are generated
+ * @return true if listener is installed; false otherwise
+ */
+ boolean isNotificationEnabled(UUID pncId);
+
+ /**
+ * HTTP POST request with specified parameters to the pnc.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param payload payload of the request as an ObjectNode
+ * @param mediaType type of content in the payload i.e. application/json
+ * @return status Commonly used status codes defined by HTTP
+ */
+ int post(UUID pncId, String request, ObjectNode payload, MediaType mediaType);
+ /**
+ * HTTP POST request with specified parameters to the pnc.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param payload payload of the request as an ObjectNode
+ * @param mediaType type of content in the payload in the form of string i.e. "application/json"
+ * @return true if status defined by HTTP is OK, CREATED, ACCEPTED or PARTIAL-CONTEND, otherwise return false
+ */
+ boolean post(UUID pncId, String request, ObjectNode payload, String mediaType);
+
+ <T> T post(UUID pncId, String request, ObjectNode payload, String mediaType, Class<T> responseClass);
+
+ <T> T post(UUID pncId, String request, ObjectNode payload, MediaType mediaType, Class<T> responseClass);
+
+ /**
+ * HTTP PUT request with specified parameters to the device.
+ *
+ * @param pncId pnc to make the request to
+ * @param request resource path of the request
+ * @param payload payload of the request as an ObjectNode
+ * @param mediaType type of content in the payload i.e. application/json
+ * @return status Commonly used status codes defined by HTTP
+ */
+ int put(UUID pncId, String request, ObjectNode payload, MediaType mediaType);
+
+ /**
+ * HTTP PUT request with specified parameters to the pnc.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param payload payload of the request as an ObjectNode
+ * @param mediaType type of content in the payload in the form of string i.e. "application/json"
+ * @return true if status defined by HTTP is OK, CREATED, ACCEPTED or PARTIAL-CONTEND, otherwise return false
+ */
+ boolean put(UUID pncId, String request, ObjectNode payload, String mediaType);
+
+ /**
+ * HTTP PATCH request with specified parameters to the device.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param payload payload of the request as an ObjectNode
+ * @param mediaType format to retrieve the content in
+ * @return status Commonly used status codes defined by HTTP
+ */
+ int patch(UUID pncId, String request, ObjectNode payload, MediaType mediaType);
+
+ /**
+ * HTTP PATCH request with specified parameters to the pnc.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param payload payload of the request as an ObjectNode
+ * @param mediaType type of content in the payload i.e. application/json
+ * @return status Commonly used status codes defined by HTTP
+ */
+ boolean patch(UUID pncId, String request, ObjectNode payload, String mediaType);
+
+ /**
+ * HTTP DELETE request with specified parameters to the device.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param mediaType type of content in the payload i.e. application/json
+ * @return status Commonly used status codes defined by HTTP
+ */
+ int delete(UUID pncId, String request, MediaType mediaType);
+
+ /**
+ * HTTP DELETE request with specified parameters to the pnc.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param mediaType type of content in the payload i.e. application/json
+ * @return status Commonly used status codes defined by HTTP
+ */
+ boolean delete(UUID pncId, String request, String mediaType);
+
+ /**
+ *
+ * HTTP GET request with specified parameters to the device.
+ *
+ * @param pncId pnc to make the request to
+ * @param request url of the request
+ * @param mediaType format to retrieve the content in
+ * @return an ObjectNode of data from the reply.
+ */
+ ObjectNode get(UUID pncId, String request, String mediaType);
+
+}
diff --git a/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestconfNotificationEventListener.java b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestconfNotificationEventListener.java
new file mode 100644
index 0000000..70eb2d6
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/RestconfNotificationEventListener.java
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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.integration.actninterfacetools.protocol.restconf;
+
+import java.util.UUID;
+
+/**
+ * Notifies providers about incoming RESTCONF notification events.
+ */
+public interface RestconfNotificationEventListener<T> {
+
+ /**
+ * Handles the notification event.
+ *
+ * @param pncId restconf device identifier
+ * @param event event payload
+ */
+ void handleNotificationEvent(UUID pncId, T event);
+}
diff --git a/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/WebClientUtil.java b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/WebClientUtil.java
new file mode 100644
index 0000000..066d4bd
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/WebClientUtil.java
@@ -0,0 +1,61 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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.integration.actninterfacetools.protocol.restconf;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class WebClientUtil {
+
+ protected static final Logger LOGGER = LoggerFactory.getLogger(WebClientUtil.class);
+
+ private WebClientUtil() {
+ }
+
+ public static String resetContentRange(String range) {
+ String rangeResult = "";
+ if (range != null) {
+ final Pattern pattern = Pattern.compile("\\d+\\-\\d+/\\S+");
+ final Matcher matcher = pattern.matcher(range);
+ if (matcher.find()) {
+ final String[] result = matcher.group(0).split("/");
+ if (result.length >= 2) {
+ final String[] ranges = result[0].split("\\D");
+ // 如果返回截止长度大于等于总长度-1,则认为结束
+ if (isContentEnd(ranges[1], result[1])) {
+ return "";
+ }
+ rangeResult = "bytes=" + (Integer.parseInt(ranges[1]) + 1) + "-"
+ + (result[1].equals("*") ? "" : result[1]);
+ }
+ }
+ }
+ return rangeResult;
+ }
+
+ private static boolean isContentEnd(String end, String total) {
+ return total.matches("[0-9]*") && Integer.parseInt(end) >= Integer.parseInt(total) - 1;
+ }
+
+}
diff --git a/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/package-info.java b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/package-info.java
new file mode 100644
index 0000000..6551498
--- /dev/null
+++ b/actn-interface-tools/restconf-client/api/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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=========================================================
+ */
+
+/**
+ * RESTCONF southbound protocols libraries.
+ */
+package org.onap.integration.actninterfacetools.protocol.restconf;
diff --git a/actn-interface-tools/restconf-client/ctl/pom.xml b/actn-interface-tools/restconf-client/ctl/pom.xml
new file mode 100644
index 0000000..6326889
--- /dev/null
+++ b/actn-interface-tools/restconf-client/ctl/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ Actn Interface Tools
+ ~ ================================================================================
+ ~ Copyright (C) 2023 Huawei Canada Limited.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>restconf-client</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <artifactId>restconf-client-ctl</artifactId>
+
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>2.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <scope>provided</scope>
+ <version>1.9.12</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ <version>5.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ <version>2.9</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient-osgi</artifactId>
+ <version>4.5.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-osgi</artifactId>
+ <version>4.4.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/RestConfSBControllerImpl.java b/actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/RestConfSBControllerImpl.java
new file mode 100644
index 0000000..71f8797
--- /dev/null
+++ b/actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/RestConfSBControllerImpl.java
@@ -0,0 +1,512 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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.integration.actninterfacetools.protocol.restconf.ctl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableMap;
+import org.apache.http.client.methods.HttpPatch;
+import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.glassfish.jersey.client.ChunkedInput;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.onap.integration.actninterfacetools.protocol.restconf.PncInstance;
+import org.onap.integration.actninterfacetools.protocol.restconf.RestConfSBController;
+import org.onap.integration.actninterfacetools.protocol.restconf.RestconfNotificationEventListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * The implementation of RestConfSBController.
+ */
+
+public class RestConfSBControllerImpl implements RestConfSBController {
+ private static volatile RestConfSBControllerImpl restConfClientInstance = null;
+ private static final int STATUS_OK = Response.Status.OK.getStatusCode();
+ private static final int STATUS_CREATED = Response.Status.CREATED.getStatusCode();
+ private static final int STATUS_ACCEPTED = Response.Status.ACCEPTED.getStatusCode();
+ private static final int PARTIAL_CONTENT = Response.Status.PARTIAL_CONTENT.getStatusCode();
+ protected static final String DOUBLESLASH = "/";
+ protected static final String COLON = ":";
+ private static final String XML = "xml";
+ private static final String JSON = "json";
+ private static final String HTTPS = "https";
+ private static final String AUTHORIZATION_PROPERTY = "authorization";
+ private static final String BASIC_AUTH_PREFIX = "Basic ";
+ private static final Logger log = LoggerFactory
+ .getLogger(RestConfSBControllerImpl.class);
+
+ // TODO: for the Ibis release when both RESTCONF server and RESTCONF client
+ // fully support root resource discovery, ROOT_RESOURCE constant will be
+ // removed and rather the value would get discovered dynamically.
+ private static final String ROOT_RESOURCE = "/restconf";
+
+ private static final String RESOURCE_PATH_PREFIX = "/data/";
+ private static final String NOTIFICATION_PATH_PREFIX = "/streams/";
+
+ private Map<UUID, Set<RestconfNotificationEventListener>>
+ restconfNotificationListenerMap = new ConcurrentHashMap<>();
+ private Map<UUID, GetChunksRunnable> runnableTable = new ConcurrentHashMap<>();
+ private final Map<UUID, PncInstance> pncMap = new ConcurrentHashMap<>();
+ private final Map<UUID, Client> clientMap = new ConcurrentHashMap<>();
+
+ ExecutorService executor = Executors.newCachedThreadPool();
+
+ private RestConfSBControllerImpl(){
+
+ }
+ public static RestConfSBControllerImpl getRestConfClient(){
+ if(restConfClientInstance != null){
+ return restConfClientInstance;
+ }
+ synchronized (RestConfSBControllerImpl.class) {
+ if(restConfClientInstance == null){
+ restConfClientInstance = new RestConfSBControllerImpl();
+
+ }
+ return restConfClientInstance;
+ }
+ }
+
+ public void activate() {
+ log.info("RESTCONF SBI Started");
+ }
+
+ public void deactivate() {
+ log.info("RESTCONF SBI Stopped");
+ executor.shutdown();
+ this.clientMap.clear();
+ this.pncMap.clear();
+ }
+
+ public Map<UUID, PncInstance> getPncInstances() {
+ log.trace("RESTCONF SBI::getDevices");
+ return ImmutableMap.copyOf(pncMap);
+ }
+
+ public PncInstance getPncInstance(UUID pncInfo) {
+ log.trace("RESTCONF SBI::getDevice with deviceId");
+ return pncMap.get(pncInfo);
+ }
+
+ public PncInstance getPncInstance(InetAddress ip, int port) {
+ log.trace("RESTCONF SBI::getDevice with ip and port");
+ return pncMap.values().stream().filter(v -> v.ip().equals(ip) && v.port() == port).findFirst().get();
+ }
+
+ public void addPncInstance(PncInstance pncInstance) {
+ log.trace("RESTCONF SBI::addDevice");
+ if (!pncMap.containsKey(pncInstance.pncId())) {
+ Client client = ignoreSslClient();
+ if (pncInstance.username() != null) {
+ String username = pncInstance.username();
+ String password = pncInstance.password() == null ? "" : pncInstance.password();
+ client.register(HttpAuthenticationFeature.basic(username, password));
+ }
+ clientMap.put(pncInstance.pncId(), client);
+ pncMap.put(pncInstance.pncId(), pncInstance);
+ } else {
+ log.warn("Trying to add a device that is already existing {}", pncInstance.pncId());
+ }
+ }
+ private Client ignoreSslClient() {
+ SSLContext sslcontext = null;
+
+ try {
+ sslcontext = SSLContext.getInstance("TLS");
+ sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
+ public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+ }
+
+ public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ }}, new java.security.SecureRandom());
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ e.printStackTrace();
+ }
+
+ return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build();
+ }
+
+ public void removeDevice(UUID pncId) {
+ log.trace("RESTCONF SBI::removeDevice");
+ clientMap.remove(pncId);
+ pncMap.remove(pncId);
+ }
+ @Override
+ public boolean post(UUID pncId, String request, ObjectNode payload,
+ String mediaType) {
+ request = discoverRootResource(pncId) + RESOURCE_PATH_PREFIX
+ + request;
+ return checkStatusCode(post(pncId, request, payload, typeOfMediaType(mediaType)));
+ }
+ private MediaType typeOfMediaType(String type) {
+ switch (type) {
+ case XML:
+ return MediaType.APPLICATION_XML_TYPE;
+ case JSON:
+ return MediaType.APPLICATION_JSON_TYPE;
+ case MediaType.WILDCARD:
+ return MediaType.WILDCARD_TYPE;
+ default:
+ throw new IllegalArgumentException("Unsupported media type " + type);
+
+ }
+ }
+ private boolean checkStatusCode(int statusCode) {
+ if (statusCode == STATUS_OK || statusCode == STATUS_CREATED || statusCode == STATUS_ACCEPTED) {
+ return true;
+ } else {
+ log.error("Failed request, HTTP error code : " + statusCode);
+ return false;
+ }
+ }
+ @Override
+ public int post(UUID pndId, String request, ObjectNode payload, MediaType mediaType) {
+ Response response = getResponse(pndId, request, payload, mediaType);
+ if (response == null) {
+ return Response.Status.NO_CONTENT.getStatusCode();
+ }
+ return response.getStatus();
+ }
+ private Response getResponse(UUID pncId, String request, ObjectNode payload, MediaType mediaType) {
+
+ WebTarget wt = getWebTarget(pncId, request);
+
+ Response response = null;
+ if (payload != null) {
+ try {
+ response = wt.request(mediaType)
+ .post(Entity.entity(payload.toString(), mediaType));
+ } catch (Exception e) {
+ log.error("Cannot do POST {} request on device {} because can't read payload", request, pncId);
+ }
+ } else {
+ response = wt.request(mediaType).post(Entity.entity(null, mediaType));
+ }
+ return response;
+ }
+ protected WebTarget getWebTarget(UUID pncId, String request) {
+ log.info("Sending request to URL {} ", getUrlString(pncId, request));
+ return clientMap.get(pncId).target(getUrlString(pncId, request));
+ }
+ protected String getUrlString(UUID pncId, String request) {
+ PncInstance pncInstance = pncMap.get(pncId);
+ if (pncInstance == null) {
+ log.warn("restSbDevice cannot be NULL!");
+ return "";
+ }
+ if (pncInstance.url() != null) {
+ return pncInstance.protocol() + COLON + DOUBLESLASH + pncInstance.url() + request;
+ } else {
+ return pncInstance.protocol() + COLON + DOUBLESLASH + pncInstance.ip().toString()
+ + COLON + pncInstance.port() + request;
+ }
+ }
+ @Override
+ public <T> T post(UUID pncId, String request, ObjectNode payload,
+ String mediaType, Class<T> responseClass) {
+ request = discoverRootResource(pncId) + RESOURCE_PATH_PREFIX
+ + request;
+ return post(pncId, request, payload, typeOfMediaType(mediaType), responseClass);
+ }
+ @Override
+ public <T> T post(UUID device, String request, ObjectNode payload, MediaType mediaType,
+ Class<T> responseClass) {
+ Response response = getResponse(device, request, payload, mediaType);
+ if (response != null && response.hasEntity()) {
+ return responseClass == Response.class ? (T) response : response.readEntity(responseClass);
+ }
+ log.error("Response from device {} for request {} contains no entity", device, request);
+ return null;
+ }
+ @Override
+ public boolean put(UUID pncId, String request, ObjectNode payload,
+ String mediaType) {
+ request = discoverRootResource(pncId) + RESOURCE_PATH_PREFIX
+ + request;
+ return checkStatusCode(put(pncId, request, payload, typeOfMediaType(mediaType)));
+ }
+ @Override
+ public int put(UUID pncId, String request, ObjectNode payload, MediaType mediaType) {
+
+ WebTarget wt = getWebTarget(pncId, request);
+
+ Response response = null;
+ if (payload != null) {
+ try {
+ response = wt.request(mediaType).put(Entity.entity(payload.toString(), mediaType));
+ } catch (Exception e) {
+ log.error("Cannot do PUT {} request on device {} because can't read payload", request, pncId);
+ }
+ } else {
+ response = wt.request(mediaType).put(Entity.entity(null, mediaType));
+ }
+
+ if (response == null) {
+ return Response.Status.NO_CONTENT.getStatusCode();
+ }
+ return response.getStatus();
+ }
+ @Override
+ public ObjectNode get(UUID pncId, String request, String mediaType) {
+ request = discoverRootResource(pncId) + RESOURCE_PATH_PREFIX
+ + request;
+ return get(pncId, request, typeOfMediaType(mediaType));
+ }
+ public ObjectNode get(UUID pncId, String request, MediaType mediaType) {
+ WebTarget wt = getWebTarget(pncId, request);
+
+ Response s = wt.request(mediaType).get();
+
+ if (checkReply(s)) {
+ try {
+ String json = s.readEntity((String.class));
+ return new ObjectMapper().readTree(json).deepCopy();
+ } catch (Exception ex) {
+ log.error("ERROR: ", ex);
+ }
+ }
+
+ return null;
+ }
+ private boolean checkReply(Response response) {
+ if (response != null) {
+ boolean statusCode = checkStatusCode(response.getStatus());
+ if (!statusCode && response.hasEntity()) {
+ log.error("Failed request, HTTP error msg : " + response.readEntity(String.class));
+ }
+ return statusCode;
+ }
+ log.error("Null reply from device");
+ return false;
+ }
+ @Override
+ public boolean patch(UUID pncId, String request, ObjectNode payload,
+ String mediaType) {
+ request = discoverRootResource(pncId) + RESOURCE_PATH_PREFIX
+ + request;
+ return checkStatusCode(patch(pncId, request, payload, typeOfMediaType(mediaType)));
+ }
+ @Override
+ public int patch(UUID pncId, String request, ObjectNode payload, MediaType mediaType) {
+
+ try {
+ log.debug("Url request {} ", getUrlString(pncId, request));
+ HttpPatch httprequest = new HttpPatch(getUrlString(pncId, request));
+ if (pncMap.get(pncId).username() != null) {
+ String pwd = pncMap.get(pncId).password() == null ? "" : COLON + pncMap.get(pncId).password();
+ String userPassword = pncMap.get(pncId).username() + pwd;
+ String base64string = Base64.getEncoder().encodeToString(userPassword.getBytes(StandardCharsets.UTF_8));
+ httprequest.addHeader(AUTHORIZATION_PROPERTY, BASIC_AUTH_PREFIX + base64string);
+ }
+ if (payload != null) {
+ StringEntity input = new StringEntity(payload.toString());
+ input.setContentType(mediaType.toString());
+ httprequest.setEntity(input);
+ }
+ CloseableHttpClient httpClient;
+ if (pncMap.containsKey(pncId) && pncMap.get(pncId).protocol().equals(HTTPS)) {
+ httpClient = getApacheSslBypassClient();
+ } else {
+ httpClient = HttpClients.createDefault();
+ }
+ return httpClient.execute(httprequest).getStatusLine().getStatusCode();
+ } catch (IOException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
+ log.error("Cannot do PATCH {} request on device {}", request, pncId, e);
+ }
+ return Response.Status.BAD_REQUEST.getStatusCode();
+ }
+ private CloseableHttpClient getApacheSslBypassClient() throws NoSuchAlgorithmException,
+ KeyManagementException, KeyStoreException {
+ return HttpClients.custom().
+ setHostnameVerifier(new AllowAllHostnameVerifier()).
+ setSslcontext(new SSLContextBuilder()
+ .loadTrustMaterial(null, (arg0, arg1) -> true)
+ .build()).build();
+ }
+ @Override
+ public boolean delete(UUID pncId, String request,
+ String mediaType) {
+ request = discoverRootResource(pncId) + RESOURCE_PATH_PREFIX
+ + request;
+ return checkStatusCode(delete(pncId, request, typeOfMediaType(mediaType)));
+ }
+ @Override
+ public int delete(UUID pncId, String request, MediaType mediaType) {
+
+ WebTarget wt = getWebTarget(pncId, request);
+
+ Response response = wt.request(mediaType).delete();
+
+ return response.getStatus();
+ }
+ @Override
+ public void enableNotifications(UUID pncId, String request,
+ String mediaType,
+ RestconfNotificationEventListener listener) {
+
+ if (isNotificationEnabled(pncId)) {
+ log.warn("enableNotifications: already enabled on device: {}", pncId);
+ return;
+ }
+
+ request = discoverRootResource(pncId) + NOTIFICATION_PATH_PREFIX
+ + request;
+
+ addNotificationListener(pncId, listener);
+
+ GetChunksRunnable runnable = new GetChunksRunnable(request, mediaType,
+ pncId);
+ runnableTable.put(pncId, runnable);
+ executor.execute(runnable);
+ }
+
+ public void stopNotifications(UUID pncId) {
+ runnableTable.get(pncId).terminate();
+ runnableTable.remove(pncId);
+ restconfNotificationListenerMap.remove(pncId);
+ log.debug("Stop sending notifications for device URI: " + pncId.toString());
+
+ }
+
+ public class GetChunksRunnable implements Runnable {
+ private String request;
+ private String mediaType;
+ private UUID pnc;
+
+ private volatile boolean running = true;
+
+ public void terminate() {
+ running = false;
+ }
+
+ /**
+ * @param request request
+ * @param mediaType media type
+ * @param pncId PNC identifier
+ */
+ public GetChunksRunnable(String request, String mediaType,
+ UUID pncId) {
+ this.request = request;
+ this.mediaType = mediaType;
+ this.pnc = pncId;
+ }
+
+ @Override
+ public void run() {
+ WebTarget wt = getWebTarget(pnc, request);
+ Response clientResp = wt.request(mediaType).get();
+ Set<RestconfNotificationEventListener> listeners =
+ restconfNotificationListenerMap.get(pnc);
+ final ChunkedInput<String> chunkedInput = (ChunkedInput<String>) clientResp
+ .readEntity(new GenericType<ChunkedInput<String>>() {
+ });
+
+ String chunk;
+ // Note that the read() is a blocking operation and the invoking
+ // thread is blocked until a new chunk comes. Jersey implementation
+ // of this IO operation is in a way that it does not respond to
+ // interrupts.
+ while (running) {
+ chunk = chunkedInput.read();
+ if (chunk != null) {
+ if (running) {
+ for (RestconfNotificationEventListener listener : listeners) {
+ listener.handleNotificationEvent(pnc, chunk);
+ }
+ } else {
+ log.trace("the requesting client is no more interested "
+ + "to receive such notifications.");
+ }
+ } else {
+ log.trace("The received notification chunk is null. do not continue any more.");
+ break;
+ }
+ }
+ log.trace("out of while loop -- end of run");
+ }
+ }
+
+ public String discoverRootResource(UUID pncId) {
+ // FIXME: send a GET command to the device to discover the root resource.
+ // The plan to fix this is for the Ibis release when the RESTCONF server and
+ // the RESTCONF client both support root resource discovery.
+ return ROOT_RESOURCE;
+ }
+
+ @Override
+ public void addNotificationListener(UUID pncId,
+ RestconfNotificationEventListener listener) {
+ Set<RestconfNotificationEventListener> listeners =
+ restconfNotificationListenerMap.get(pncId);
+ if (listeners == null) {
+ listeners = new HashSet<>();
+ }
+
+ listeners.add(listener);
+
+ this.restconfNotificationListenerMap.put(pncId, listeners);
+ }
+
+ @Override
+ public void removeNotificationListener(UUID pncId,
+ RestconfNotificationEventListener listener) {
+ Set<RestconfNotificationEventListener> listeners =
+ restconfNotificationListenerMap.get(pncId);
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+
+ public boolean isNotificationEnabled(UUID pncId) {
+ return runnableTable.containsKey(pncId);
+ }
+}
diff --git a/actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/package-info.java b/actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/package-info.java
new file mode 100644
index 0000000..a672161
--- /dev/null
+++ b/actn-interface-tools/restconf-client/ctl/src/main/java/org/onap/integration/actninterfacetools/protocol/restconf/ctl/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Actn Interface Tools
+ * ================================================================================
+ * Copyright (C) 2023 Huawei Canada Limited.
+ * ================================================================================
+ * 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=========================================================
+ */
+
+/**
+ * RESTCONF southbound protocol implementation.
+ */
+package org.onap.integration.actninterfacetools.protocol.restconf.ctl;
diff --git a/actn-interface-tools/restconf-client/pom.xml b/actn-interface-tools/restconf-client/pom.xml
new file mode 100644
index 0000000..f115180
--- /dev/null
+++ b/actn-interface-tools/restconf-client/pom.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ Actn Interface Tools
+ ~ ================================================================================
+ ~ Copyright (C) 2023 Huawei Canada Limited.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>actn-interface-tools</artifactId>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>restconf-client</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <scope>provided</scope>
+ <version>1.9.12</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ <version>5.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>2.8.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ <version>2.9</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>2.3.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient-osgi</artifactId>
+ <version>4.5.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-osgi</artifactId>
+ <version>4.4.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ </dependencies>
+ <modules>
+ <module>api</module>
+ <module>ctl</module>
+ </modules>
+ <description>RESTCONF Client Module</description>
+</project>
diff --git a/actn-interface-tools/yang-utils/pom.xml b/actn-interface-tools/yang-utils/pom.xml
new file mode 100644
index 0000000..6fc3a7c
--- /dev/null
+++ b/actn-interface-tools/yang-utils/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ Actn Interface Tools
+ ~ ================================================================================
+ ~ Copyright (C) 2022 Huawei Canada Limited.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.integration.ietf-actn-tools</groupId>
+ <artifactId>actn-interface-tools</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>yang-utils</artifactId>
+</project>