Merge "SOL003 Adapter Package Management - Notify"
authorByung-Woo Jun <byung-woo.jun@est.tech>
Mon, 24 Feb 2020 16:19:04 +0000 (16:19 +0000)
committerGerrit Code Review <gerrit@onap.org>
Mon, 24 Feb 2020 16:19:04 +0000 (16:19 +0000)
21 files changed:
adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationController.java
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/ConversionFailedException.java [moved from adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/SubscriptionRequestConversionException.java with 83% similarity]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java [new file with mode: 0644]
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java
adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java [new file with mode: 0644]

index 6f9b2c3..6db5443 100644 (file)
@@ -6,18 +6,26 @@
     "version": "v1"
   },
   "host": "127.0.0.1:8000",
-  "schemes": ["http"],
+  "schemes": [
+    "http"
+  ],
   "basePath": "/",
-  "consumes": ["application/json"],
-  "produces": ["application/json"],
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
   "securityDefinitions": {
     "Basic": {
       "type": "basic"
     }
   },
-  "security": [{
-    "Basic": []
-  }],
+  "security": [
+    {
+      "Basic": []
+    }
+  ],
   "paths": {
     "/URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification": {
       "get": {
             }
           }
         },
-        "tags": ["VNF Package Management interface"]
+        "tags": [
+          "VNF Package Management interface"
+        ]
       },
       "post": {
         "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification_create",
         "description": "",
-        "parameters": [{
-          "name": "data",
-          "in": "body",
-          "required": true,
-          "schema": {
-            "$ref": "#/definitions/PkgChangeNotification"
+        "parameters": [
+          {
+            "name": "data",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/PkgChangeNotification"
+            }
           }
-        }],
+        ],
         "responses": {
           "204": {
             "description": ""
           }
         },
-        "tags": ["VNF Package Management interface"]
+        "tags": [
+          "VNF Package Management interface"
+        ]
       },
       "parameters": []
     },
             }
           }
         },
-        "tags": ["VNF Package Management interface"]
+        "tags": [
+          "VNF Package Management interface"
+        ]
       },
       "post": {
         "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageOnboardingNotification_create",
         "description": "",
-        "parameters": [{
-          "name": "data",
-          "in": "body",
-          "required": true,
-          "schema": {
-            "$ref": "#/definitions/PkgOnboardingNotification"
+        "parameters": [
+          {
+            "name": "data",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/PkgOnboardingNotification"
+            }
           }
-        }],
+        ],
         "responses": {
           "204": {
             "description": ""
           }
         },
-        "tags": ["VNF Package Management interface"]
+        "tags": [
+          "VNF Package Management interface"
+        ]
       },
       "parameters": []
     }
     "NOTIFICATION_LINKSERIALIZER": {
       "title": "Vnfpackage",
       "description": "Link to the resource representing the VNF package to which the notified change applies.",
-      "required": ["href"],
+      "required": [
+        "href"
+      ],
       "type": "object",
       "properties": {
         "href": {
       }
     },
     "PkgChangeNotification": {
-      "required": ["id", "notificationType", "timeStamp", "subscriptionId", "vnfPkgId", "changeType", "vnfdId", "_links"],
+      "required": [
+        "id",
+        "notificationType",
+        "timeStamp",
+        "subscriptionId",
+        "vnfPkgId",
+        "changeType",
+        "vnfdId",
+        "_links"
+      ],
       "type": "object",
       "properties": {
         "id": {
           "title": "Notificationtype",
           "description": "Discriminator for the different notification types.",
           "type": "string",
-          "enum": ["VnfPackageChangeNotification"]
+          "enum": [
+            "VnfPackageChangeNotification"
+          ]
         },
         "timeStamp": {
           "title": "Timestamp",
           "title": "Vnfpkgid",
           "description": "Identifier of the VNF package.",
           "type": "string",
-          "format": "uuid"
+          "minLength": 1
         },
         "changeType": {
           "title": "Changetype",
           "description": "The type of change of the VNF package.",
           "type": "string",
-          "enum": ["OP_STATE_CHANGE", "PKG_DELETE"]
+          "enum": [
+            "OP_STATE_CHANGE",
+            "PKG_DELETE"
+          ]
         },
         "operationalState": {
           "title": "Operationalstate",
           "description": "New operational state of the VNF package.",
           "type": "string",
-          "enum": ["ENABLED", "DISABLED"]
+          "enum": [
+            "ENABLED",
+            "DISABLED"
+          ]
         },
         "vnfdId": {
           "title": "Vnfdid",
       }
     },
     "PkgOnboardingNotification": {
-      "required": ["id", "notificationType", "subscriptionId", "timeStamp", "vnfPkgId", "vnfdId", "_links"],
+      "required": [
+        "id",
+        "notificationType",
+        "subscriptionId",
+        "timeStamp",
+        "vnfPkgId",
+        "vnfdId",
+        "_links"
+      ],
       "type": "object",
       "properties": {
         "id": {
           "title": "Notificationtype",
           "description": "Discriminator for the different notification types.",
           "type": "string",
-          "enum": ["VnfPackageOnboardingNotification"]
+          "enum": [
+            "VnfPackageOnboardingNotification"
+          ]
         },
         "subscriptionId": {
           "title": "Subscriptionid",
           "title": "Vnfpkgid",
           "description": "Identifier of the VNF package.",
           "type": "string",
-          "format": "uuid"
+          "minLength": 1
         },
         "vnfdId": {
           "title": "Vnfdid",
           "description": "This identifier, which is managed by the VNF provider, identifies the VNF package and the VNFD in a globally unique way.",
           "type": "string",
-          "format": "uuid"
+          "minLength": 1
         },
         "_links": {
           "$ref": "#/definitions/PkgmLinks"
       }
     }
   }
-}
\ No newline at end of file
+}
index 61d5adf..87e8bb4 100644 (file)
@@ -23,6 +23,8 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import java.util.ArrayList;
 import java.util.Collection;
+import org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003.PkgChangeNotificationConverter;
+import org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003.PkgOnboardingNotificationConverter;
 import org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003.VnfPkgInfoConverter;
 import org.onap.so.adapters.vnfmadapter.converters.sol003.etsicatalog.PkgmSubscriptionRequestConverter;
 import org.onap.so.adapters.vnfmadapter.oauth.OAuth2AccessTokenAdapter;
@@ -46,6 +48,8 @@ public class MessageConverterConfiguration {
         final DefaultConversionService service = new DefaultConversionService();
         service.addConverter(new VnfPkgInfoConverter());
         service.addConverter(new PkgmSubscriptionRequestConverter());
+        service.addConverter(new PkgChangeNotificationConverter());
+        service.addConverter(new PkgOnboardingNotificationConverter());
         return service;
     }
 
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java
new file mode 100644 (file)
index 0000000..e1c4309
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003;
+
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgmLinks;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage;
+
+/**
+ * A base class that can be extended by classes for converting Etsi Catalog Manager Pkg Notification classes. Provides
+ * common methods that will be useful to those classes.
+ *
+ * @author andrew.a.lamb@est.tech
+ */
+abstract public class AbstractPkgNotificationConverter {
+
+    protected URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks convert(
+            final PkgmLinks pkgmLinks) {
+        final URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage linksVnfPackage =
+                new URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage();
+        if (pkgmLinks.getVnfPackage() != null) {
+            linksVnfPackage.setHref(pkgmLinks.getVnfPackage().getHref());
+        }
+
+        final URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage linksSubscription =
+                new URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage();
+        if (pkgmLinks.getSubscription() != null) {
+            linksSubscription.setHref(pkgmLinks.getSubscription().getHref());
+        }
+
+        final URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks links =
+                new URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks();
+        links.setVnfPackage(linksVnfPackage);
+        links.setSubscription(linksSubscription);
+        return links;
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java
new file mode 100644 (file)
index 0000000..8c41686
--- /dev/null
@@ -0,0 +1,79 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageChangeNotification;
+import org.slf4j.Logger;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Service;
+
+/**
+ * Converter to convert from an Etsi Catalog Manager {@link PkgChangeNotification} Object to its equivalent SOL003
+ * {@link VnfPackageChangeNotification} Object
+ *
+ * @author andrew.a.lamb@est.tech
+ */
+@Service
+public class PkgChangeNotificationConverter extends AbstractPkgNotificationConverter
+        implements Converter<PkgChangeNotification, VnfPackageChangeNotification> {
+    private static final Logger logger = getLogger(PkgChangeNotificationConverter.class);
+
+    /**
+     * Convert a {@link PkgChangeNotification} Object to an {@link VnfPackageChangeNotification} Object
+     * 
+     * @param pkgChangeNotification The PkgChangeNotification Object to Convert
+     * @return The Converted VnfPackageChangeNotification Object
+     */
+    @Override
+    public VnfPackageChangeNotification convert(final PkgChangeNotification pkgChangeNotification) {
+        logger.info("Converting PkgChangeNotification\n{}", pkgChangeNotification.toString());
+        final VnfPackageChangeNotification vnfPackageChangeNotification = new VnfPackageChangeNotification();
+        vnfPackageChangeNotification.setId(pkgChangeNotification.getId());
+
+        if (pkgChangeNotification.getNotificationType() != null) {
+            vnfPackageChangeNotification.setNotificationType(VnfPackageChangeNotification.NotificationTypeEnum
+                    .fromValue(pkgChangeNotification.getNotificationType().getValue()));
+        }
+
+        vnfPackageChangeNotification.setSubscriptionId(pkgChangeNotification.getSubscriptionId());
+        vnfPackageChangeNotification.setTimeStamp(pkgChangeNotification.getTimeStamp());
+        vnfPackageChangeNotification.setVnfPkgId(pkgChangeNotification.getVnfPkgId());
+
+        vnfPackageChangeNotification.setVnfdId(pkgChangeNotification.getVnfdId());
+
+        if (pkgChangeNotification.getChangeType() != null) {
+            vnfPackageChangeNotification.setChangeType(VnfPackageChangeNotification.ChangeTypeEnum
+                    .fromValue(pkgChangeNotification.getChangeType().getValue()));
+        }
+
+        if (pkgChangeNotification.getOperationalState() != null) {
+            vnfPackageChangeNotification.setOperationalState(VnfPackageChangeNotification.OperationalStateEnum
+                    .fromValue(pkgChangeNotification.getOperationalState().getValue()));
+        }
+
+        vnfPackageChangeNotification.setLinks(convert((pkgChangeNotification.getLinks())));
+
+        return vnfPackageChangeNotification;
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java
new file mode 100644 (file)
index 0000000..836acb6
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageOnboardingNotification;
+import org.slf4j.Logger;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Service;
+
+/**
+ * Converter to convert from an Etsi Catalog Manager {@link PkgOnboardingNotification} Object to its equivalent SOL003
+ * {@link VnfPackageOnboardingNotification} Object
+ *
+ * @author andrew.a.lamb@est.tech
+ */
+@Service
+public class PkgOnboardingNotificationConverter extends AbstractPkgNotificationConverter
+        implements Converter<PkgOnboardingNotification, VnfPackageOnboardingNotification> {
+    private static final Logger logger = getLogger(PkgOnboardingNotificationConverter.class);
+
+    /**
+     * Convert a {@link PkgOnboardingNotification} Object to an {@link VnfPackageOnboardingNotification} Object
+     * 
+     * @param pkgOnboardingNotification The PkgOnboardingNotification Object to Convert
+     * @return The Converted VnfPackageOnboardingNotification Object
+     */
+    @Override
+    public VnfPackageOnboardingNotification convert(final PkgOnboardingNotification pkgOnboardingNotification) {
+        logger.info("Converting PkgChangeNotification\n{}", pkgOnboardingNotification.toString());
+        final VnfPackageOnboardingNotification vnfPackageOnboardingNotification =
+                new VnfPackageOnboardingNotification();
+        vnfPackageOnboardingNotification.setId(pkgOnboardingNotification.getId());
+
+        if (pkgOnboardingNotification.getNotificationType() != null) {
+            vnfPackageOnboardingNotification.setNotificationType(VnfPackageOnboardingNotification.NotificationTypeEnum
+                    .fromValue(pkgOnboardingNotification.getNotificationType().getValue()));
+        }
+
+        vnfPackageOnboardingNotification.setSubscriptionId(pkgOnboardingNotification.getSubscriptionId());
+        vnfPackageOnboardingNotification.setTimeStamp(pkgOnboardingNotification.getTimeStamp());
+        vnfPackageOnboardingNotification.setVnfPkgId(pkgOnboardingNotification.getVnfPkgId());
+        vnfPackageOnboardingNotification.setVnfdId(pkgOnboardingNotification.getVnfdId());
+
+        vnfPackageOnboardingNotification.setLinks(convert((pkgOnboardingNotification.getLinks())));
+
+        return vnfPackageOnboardingNotification;
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java
new file mode 100644 (file)
index 0000000..86ca59c
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.codec.binary.Base64;
+import org.onap.so.configuration.rest.BasicHttpHeadersProvider;
+import org.onap.so.configuration.rest.HttpHeadersProvider;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.onap.so.rest.service.HttpRestServiceProviderImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * A base class that can be extended by classes for providing notification services. Provides common methods that will
+ * be useful to those classes.
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+public abstract class AbstractNotificationServiceProvider {
+
+    @Autowired
+    @Qualifier(CONFIGURABLE_REST_TEMPLATE)
+    private RestTemplate restTemplate;
+
+    protected HttpRestServiceProvider getHttpRestServiceProvider(final HttpHeadersProvider httpHeadersProvider) {
+        final HttpRestServiceProvider httpRestServiceProvider =
+                new HttpRestServiceProviderImpl(restTemplate, httpHeadersProvider);
+        return httpRestServiceProvider;
+    }
+
+    protected BasicHttpHeadersProvider getBasicHttpHeadersProviderWithBasicAuth(final String username,
+            final String password) {
+        final byte[] encodedAuth = getBasicAuth(username, password);
+        final String authHeader = "Basic " + new String(encodedAuth);
+        return new BasicHttpHeadersProvider(authHeader);
+    }
+
+    protected byte[] getBasicAuth(final String username, final String password) {
+        final String auth = username + ":" + password;
+        return Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java
new file mode 100644 (file)
index 0000000..6f9d94e
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum;
+import org.onap.so.configuration.rest.HttpHeadersProvider;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.slf4j.Logger;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+/**
+ * Implementation of a NotificationServiceProvider which supports Basic Authentication
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@Service
+public class BasicAuthNotificationServiceProvider extends AbstractNotificationServiceProvider
+        implements NotificationServiceProvider {
+
+    private static final Logger logger = getLogger(BasicAuthNotificationServiceProvider.class);
+
+    @Override
+    public boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication,
+            final String callbackUri) {
+        logger.info("Sending notification to uri: {}", callbackUri);
+        final HttpHeadersProvider httpHeadersProvider =
+                getBasicHttpHeadersProviderWithBasicAuth(subscriptionsAuthentication.getParamsBasic().getUserName(),
+                        subscriptionsAuthentication.getParamsBasic().getPassword());
+        final HttpRestServiceProvider httpRestServiceProvider = getHttpRestServiceProvider(httpHeadersProvider);
+
+        final ResponseEntity<Void> responseEntity =
+                httpRestServiceProvider.postHttpRequest(notification, callbackUri, Void.class);
+        if (responseEntity.getStatusCode().is2xxSuccessful()) {
+            logger.info("Notification sent successfully.");
+            return true;
+        }
+
+        logger.error("Failed to send notification.");
+        return false;
+    }
+
+    @Override
+    public AuthTypeEnum getAuthType() {
+        return AuthTypeEnum.BASIC;
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java
new file mode 100644 (file)
index 0000000..c1051d1
--- /dev/null
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.util.List;
+import java.util.Optional;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageChangeNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageOnboardingNotification;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.AuthenticationTypeNotSupportedException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.ConversionFailedException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.NotificationTypeNotSupportedException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.SubscriptionNotFoundException;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.convert.ConversionService;
+import org.springframework.stereotype.Service;
+
+/**
+ * Manages package management subscription notifications to the VNFMs
+ *
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+@Service
+public class NotificationManager {
+
+    private static final Logger logger = getLogger(NotificationManager.class);
+    private final ConversionService conversionService;
+    private final SubscriptionManager subscriptionManager;
+    private final NotificationServiceProviderFactory notificationServiceProviderFactory;
+
+    @Autowired
+    public NotificationManager(final SubscriptionManager subscriptionManager, final ConversionService conversionService,
+            final NotificationServiceProviderFactory notificationServiceProviderFactory) {
+        this.subscriptionManager = subscriptionManager;
+        this.conversionService = conversionService;
+        this.notificationServiceProviderFactory = notificationServiceProviderFactory;
+    }
+
+    /**
+     * Process a subscription notification. Checks for a subscription request stored in the adapter and if there is, it
+     * sends the notification to the subscribed vnfm.
+     * 
+     * @param notification the notification to send to the vnfm
+     * @param subscriptionId the id of the subscription request
+     * @return true if the notification is successfully sent
+     */
+    public boolean processSubscriptionNotification(final Object notification, final String subscriptionId) {
+        final Optional<PkgmSubscriptionRequest> optionalSubscription =
+                subscriptionManager.getSubscriptionRequest(subscriptionId);
+        if (optionalSubscription.isPresent()) {
+            final PkgmSubscriptionRequest subscriptionRequest = optionalSubscription.get();
+            return notifyVnfm(subscriptionRequest, notification);
+        }
+        final String errorMessage = "No subscription found with subscriptionId " + subscriptionId
+                + ". Unable to forward notification to subscriber.";
+        logger.error(errorMessage);
+        throw new SubscriptionNotFoundException(errorMessage);
+    }
+
+    private boolean notifyVnfm(final PkgmSubscriptionRequest subscriptionRequest, final Object notification) {
+        if (!(notification instanceof PkgOnboardingNotification) && !(notification instanceof PkgChangeNotification)) {
+            final String errorMessage =
+                    "An error occurred.  Notification type not supported for: " + notification.getClass();
+            logger.error(errorMessage);
+            throw new NotificationTypeNotSupportedException(errorMessage);
+        }
+
+        final SubscriptionsAuthentication subscriptionsAuthentication = subscriptionRequest.getAuthentication();
+        final AuthTypeEnum authType = getAuthType(subscriptionsAuthentication.getAuthType());
+        final NotificationServiceProvider sender = notificationServiceProviderFactory.getNotificationSender(authType);
+
+        final Object vnfmNotificationObject = convertEtsiCatalogNotification(notification);
+
+        if (sender.send(vnfmNotificationObject, subscriptionsAuthentication, subscriptionRequest.getCallbackUri())) {
+            logger.info("Notification delivered successfully {}", notification);
+            return true;
+        }
+
+        logger.error("Failed to deliver notification.");
+        return false;
+    }
+
+    private SubscriptionsAuthentication.AuthTypeEnum getAuthType(final List<AuthTypeEnum> authTypes) {
+        if (authTypes.contains(SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT)) {
+            return SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT;
+        }
+        if (authTypes.contains(SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS)) {
+            return SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS;
+        }
+        if (authTypes.contains(SubscriptionsAuthentication.AuthTypeEnum.BASIC)) {
+            return SubscriptionsAuthentication.AuthTypeEnum.BASIC;
+        }
+        final String errorMessage =
+                "An error occurred. No supported authentication type provided in subscription request.";
+        logger.error(errorMessage);
+        throw new AuthenticationTypeNotSupportedException(errorMessage);
+    }
+
+    private Object convertEtsiCatalogNotification(final Object etsiCatalogNotification) {
+        logger.info("Converting notification:\n {}", etsiCatalogNotification);
+        if (conversionService.canConvert(etsiCatalogNotification.getClass(), VnfPackageOnboardingNotification.class)) {
+            return conversionService.convert(etsiCatalogNotification, VnfPackageOnboardingNotification.class);
+        } else if (conversionService.canConvert(etsiCatalogNotification.getClass(),
+                VnfPackageChangeNotification.class)) {
+            return conversionService.convert(etsiCatalogNotification, VnfPackageChangeNotification.class);
+        }
+        final String errorMessage = "An error occurred. Unable to convert provided notification object.";
+        logger.error(errorMessage + "\n" + etsiCatalogNotification);
+        throw new ConversionFailedException(errorMessage);
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java
new file mode 100644 (file)
index 0000000..2be80ee
--- /dev/null
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum;
+
+/**
+ * Interface which lays out requirements for a Notification Service Provider
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+public interface NotificationServiceProvider {
+
+    /**
+     * Method to send a notification to a uri, given the subscription authentication
+     * 
+     * @param notification The notification to send
+     * @param subscriptionsAuthentication Object containing the authentication details
+     * @param callbackUri The uri to send the notification to
+     * @return true if notification is delivered successfully, otherwise false
+     */
+    boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication,
+            final String callbackUri);
+
+    /**
+     * Method to get the supported authorization type of the service provider
+     * 
+     * @return the supported AuthTypeEnum
+     */
+    AuthTypeEnum getAuthType();
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java
new file mode 100644 (file)
index 0000000..ab67afe
--- /dev/null
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.AuthenticationTypeNotSupportedException;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Factory to provide a notification services
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@Component
+public class NotificationServiceProviderFactory {
+
+    private static final Logger logger = getLogger(NotificationServiceProviderFactory.class);
+    private static final Map<AuthTypeEnum, NotificationServiceProvider> CACHE = new HashMap<>();
+
+    @Autowired
+    public NotificationServiceProviderFactory(final List<NotificationServiceProvider> services) {
+        for (final NotificationServiceProvider notificationServiceProvider : services) {
+            logger.debug("Adding {} of type {} to cache", notificationServiceProvider.getClass().getCanonicalName(),
+                    notificationServiceProvider.getAuthType());
+            CACHE.put(notificationServiceProvider.getAuthType(), notificationServiceProvider);
+        }
+    }
+
+    /**
+     * Get a notification service for a given authorization type
+     * 
+     * @param type the type of authentication required
+     * @return the notification service
+     */
+    public NotificationServiceProvider getNotificationSender(final AuthTypeEnum type) {
+        final NotificationServiceProvider service = CACHE.get(type);
+        if (service == null) {
+            throw new AuthenticationTypeNotSupportedException("Unknown type: " + type);
+        }
+        return service;
+    }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java
new file mode 100644 (file)
index 0000000..496fb08
--- /dev/null
@@ -0,0 +1,102 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.InternalServerErrorException;
+import org.onap.so.configuration.rest.BasicHttpHeadersProvider;
+import org.onap.so.configuration.rest.HttpHeadersProvider;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.slf4j.Logger;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+@Service
+public class OAuthNotificationServiceProvider extends AbstractNotificationServiceProvider
+        implements NotificationServiceProvider {
+
+    private static final Logger logger = getLogger(OAuthNotificationServiceProvider.class);
+
+    @Override
+    public boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication,
+            final String callbackUri) {
+        logger.info("Sending notification to uri: {}", callbackUri);
+        final String token = getAccessToken(subscriptionsAuthentication);
+
+        if (token == null) {
+            return false;
+        }
+
+        final HttpHeadersProvider httpHeadersProvider = getHttpHeadersProvider(token);
+        final HttpRestServiceProvider httpRestServiceProvider = getHttpRestServiceProvider(httpHeadersProvider);
+        final ResponseEntity<Void> responseEntity =
+                httpRestServiceProvider.postHttpRequest(notification, callbackUri, Void.class);
+        if (responseEntity.getStatusCode().is2xxSuccessful()) {
+            logger.info("Notification sent successfully.");
+            return true;
+        }
+
+        logger.error("Failed to send notification.");
+        return false;
+    }
+
+    @Override
+    public AuthTypeEnum getAuthType() {
+        return AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS;
+    }
+
+    private BasicHttpHeadersProvider getHttpHeadersProvider(final String token) {
+        final String authHeader = "Bearer " + token;
+        return new BasicHttpHeadersProvider(authHeader);
+    }
+
+    private String getAccessToken(final SubscriptionsAuthentication subscriptionsAuthentication) {
+        logger.info("Requesting Access Token.");
+
+        final String tokenEndpoint = subscriptionsAuthentication.getParamsOauth2ClientCredentials().getTokenEndpoint();
+
+        final HttpHeadersProvider httpHeadersProvider = getBasicHttpHeadersProviderWithBasicAuth(
+                subscriptionsAuthentication.getParamsOauth2ClientCredentials().getClientId(),
+                subscriptionsAuthentication.getParamsOauth2ClientCredentials().getClientPassword());
+
+        final HttpRestServiceProvider httpRestServiceProvider = getHttpRestServiceProvider(httpHeadersProvider);
+        final ResponseEntity<OAuthTokenResponse> responseEntity =
+                httpRestServiceProvider.postHttpRequest(null, tokenEndpoint, OAuthTokenResponse.class);
+        if (responseEntity.getStatusCode().is2xxSuccessful()) {
+            if (responseEntity.getBody() != null) {
+                logger.info("Returning Access Token.");
+                return responseEntity.getBody().getAccessToken();
+            }
+        }
+
+        final String errorMessage = "An error occurred.  Unable to retrieve OAuth Token from VNFM for notification.";
+        logger.error(errorMessage);
+        throw new InternalServerErrorException(errorMessage);
+    }
+
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java
new file mode 100644 (file)
index 0000000..146641c
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlElement;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+public class OAuthTokenResponse implements Serializable {
+
+    private static final long serialVersionUID = -6455742984985959926L;
+
+    @XmlElement(name = "access_token")
+    @SerializedName("access_token")
+    private String accessToken;
+
+    /**
+     * Get the Accees Token
+     *
+     * @return the Access Token
+     */
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    /**
+     * Set the Access Token
+     *
+     * @param accessToken
+     */
+    public void setAccessToken(final String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+}
index d02bd9a..a4c52fd 100644 (file)
@@ -41,12 +41,11 @@ import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.
 import org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement.cache.PackageManagementCacheServiceProvider;
 import org.onap.so.adapters.vnfmadapter.rest.exceptions.InternalServerErrorException;
 import org.onap.so.adapters.vnfmadapter.rest.exceptions.SubscriptionNotFoundException;
-import org.onap.so.adapters.vnfmadapter.rest.exceptions.SubscriptionRequestConversionException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.ConversionFailedException;
 import org.onap.so.utils.CryptoUtils;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.convert.ConversionException;
 import org.springframework.core.convert.ConversionService;
 import org.springframework.stereotype.Service;
 
@@ -67,7 +66,6 @@ public class SubscriptionManager {
     private final String msoKeyString;
     private final String vnfmAdapterAuth;
 
-
     @Autowired
     public SubscriptionManager(final PackageManagementCacheServiceProvider packageManagementCacheServiceProvider,
             final ConversionService conversionService, final EtsiCatalogServiceProvider etsiCatalogServiceProvider,
@@ -112,7 +110,6 @@ public class SubscriptionManager {
                 "Received empty response from POST to ETSI Catalog Manager Subscription Endpoint.");
     }
 
-
     public Optional<String> getSubscriptionId(final PkgmSubscriptionRequest pkgmSubscriptionRequest) {
         return packageManagementCacheServiceProvider.getSubscriptionId(pkgmSubscriptionRequest);
     }
@@ -174,6 +171,10 @@ public class SubscriptionManager {
                 vnfmAdapterEndpoint + Constants.PACKAGE_MANAGEMENT_BASE_URL + "/subscriptions/" + subscriptionId);
     }
 
+    public Optional<PkgmSubscriptionRequest> getSubscriptionRequest(final String subscriptionId) {
+        return packageManagementCacheServiceProvider.getSubscription(subscriptionId);
+    }
+
     private InlineResponse2002 getInlineResponse2002(final String id, final PkgmSubscriptionRequest subscription) {
         return new InlineResponse2002().id(id).filter(subscription.getFilter())
                 .callbackUri(subscription.getCallbackUri());
@@ -186,9 +187,9 @@ public class SubscriptionManager {
         try {
             etsiCatalogManagerSubscriptionRequest = conversionService.convert(pkgmSubscriptionRequest,
                     org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.PkgmSubscriptionRequest.class);
-        } catch (final ConversionException conversionException) {
+        } catch (final org.springframework.core.convert.ConversionException conversionException) {
             logger.error(conversionException.getMessage());
-            throw new SubscriptionRequestConversionException(
+            throw new ConversionFailedException(
                     "Could not convert Sol003 PkgmSubscriptionRequest to ETSI-Catalog Manager PkgmSubscriptionRequest");
         } catch (final Exception exception) {
             logger.error(exception.getMessage());
@@ -209,7 +210,7 @@ public class SubscriptionManager {
                             .addAuthTypeItem(BASIC).paramsBasic(new BasicAuth().userName(username).password(password)));
             return etsiCatalogManagerSubscriptionRequest;
         }
-        throw new SubscriptionRequestConversionException(
+        throw new ConversionFailedException(
                 "Failed to convert Sol003 PkgmSubscriptionRequest to ETSI-Catalog Manager PkgmSubscriptionRequest");
     }
 
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java
new file mode 100644 (file)
index 0000000..c9babbd
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.AuthenticationTypeNotSupportedException;
+import org.slf4j.Logger;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@Service
+public class TlsNotificationServiceProvider extends AbstractNotificationServiceProvider
+        implements NotificationServiceProvider {
+
+    private static final Logger logger = getLogger(TlsNotificationServiceProvider.class);
+
+    @Override
+    public boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication,
+            final String callbackUri) {
+        final String errorMessage = "An error occurred.  Authentication type "
+                + subscriptionsAuthentication.getAuthType().toString() + " not currently supported.";
+        logger.error(errorMessage);
+        throw new AuthenticationTypeNotSupportedException(errorMessage);
+    }
+
+
+    @Override
+    public AuthTypeEnum getAuthType() {
+        return AuthTypeEnum.TLS_CERT;
+    }
+
+
+
+}
index a2f44f9..a97f04b 100644 (file)
@@ -22,27 +22,110 @@ package org.onap.so.adapters.vnfmadapter.rest;
 
 import static org.onap.so.adapters.vnfmadapter.Constants.ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL;
 import static org.slf4j.LoggerFactory.getLogger;
+import java.util.AbstractMap;
+import java.util.Map.Entry;
+import javax.ws.rs.core.MediaType;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification;
+import org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement.NotificationManager;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.InternalServerErrorException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.NotificationTypeNotSupportedException;
 import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
 
 /**
  * This controller handles the ETSI Subscription Notification Endpoints.
  *
  * @author Ronan Kenny (ronan.kenny@est.tech)
  * @author Gareth Roper (gareth.roper@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
  */
 @Controller
 @RequestMapping(value = ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL)
 public class EtsiSubscriptionNotificationController {
 
     private static final Logger logger = getLogger(EtsiSubscriptionNotificationController.class);
+    private final NotificationManager notificationManager;
+    private final Gson gson;
+
+    @Autowired
+    public EtsiSubscriptionNotificationController(final NotificationManager notificationManager) {
+        this.notificationManager = notificationManager;
+        this.gson = new GsonBuilder().create();
+    }
 
     @GetMapping(value = "/notification")
     public ResponseEntity<Void> testSubscriptionNotificationEndPoint() {
         logger.debug("Testing Notification Endpoint");
         return ResponseEntity.noContent().build();
     }
+
+    /**
+     * POST notification on to subscriber.
+     * 
+     * @param notification The notification to send.
+     * @return Response Code: 204 No Content if Successful, ProblemDetails Object if not.
+     */
+    @PostMapping(value = "/notification", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
+    public ResponseEntity<?> postSubscriptionNotification(@RequestBody final String notification) {
+        logger.info("Posting subscription notification \n{}", notification);
+
+        final Entry<String, Object> notificationObject = getNotificationObject(notification);
+        if (notificationManager.processSubscriptionNotification(notificationObject.getValue(),
+                notificationObject.getKey())) {
+            logger.info("Notification Delivered Successfully");
+            return ResponseEntity.noContent().build();
+        }
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed.";
+        logger.error(errorMessage);
+        throw new InternalServerErrorException(errorMessage);
+    }
+
+    private Entry<String, Object> getNotificationObject(final String notification) {
+        final String notificationType = getNotificationType(notification);
+        if (PkgOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION.getValue()
+                .equals(notificationType)) {
+            final PkgOnboardingNotification pkgOnboardingNotification =
+                    gson.fromJson(notification, PkgOnboardingNotification.class);
+            logger.info("Onboarding notification received:\n{}", pkgOnboardingNotification);
+            return new AbstractMap.SimpleEntry<>(pkgOnboardingNotification.getSubscriptionId(),
+                    pkgOnboardingNotification);
+        }
+        if (PkgChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION.getValue()
+                .equals(notificationType)) {
+            final PkgChangeNotification pkgChangeNotification =
+                    gson.fromJson(notification, PkgChangeNotification.class);
+            logger.info("Change notification received:\n{}", pkgChangeNotification);
+            return new AbstractMap.SimpleEntry<>(pkgChangeNotification.getSubscriptionId(), pkgChangeNotification);
+
+        }
+
+        final String errorMessage = "An error occurred.  Notification type not supported for: " + notificationType;
+        logger.error(errorMessage);
+        throw new NotificationTypeNotSupportedException(errorMessage);
+
+    }
+
+    private String getNotificationType(final String notification) {
+        try {
+            final JsonParser parser = new JsonParser();
+            final JsonObject element = (JsonObject) parser.parse(notification);
+            return element.get("notificationType").getAsString();
+        } catch (final Exception e) {
+            logger.error("An error occurred processing notificiation: {}", e.getMessage());
+        }
+        throw new NotificationTypeNotSupportedException(
+                "Unable to parse notification type in object \n" + notification);
+    }
+
 }
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java
new file mode 100644 (file)
index 0000000..303420f
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.rest.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Exception for an unsupported authentication type
+ * 
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
+public class AuthenticationTypeNotSupportedException extends RuntimeException {
+
+    private static final long serialVersionUID = 2939423208362066902L;
+
+    public AuthenticationTypeNotSupportedException(final String message) {
+        super(message);
+    }
+
+    @Override
+    public synchronized Throwable fillInStackTrace() {
+        return this;
+    }
+
+}
@@ -23,16 +23,17 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 /**
- * Exception for an ETSI Catalog Manager Request Failure
+ * Exception for Conversion Failures
  * 
- * @author gareth.roper@est.tech
+ * @author Gareth Roper (gareth.roper@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
  */
 @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
-public class SubscriptionRequestConversionException extends RuntimeException {
+public class ConversionFailedException extends RuntimeException {
 
     private static final long serialVersionUID = 45898561453196895L;
 
-    public SubscriptionRequestConversionException(final String message) {
+    public ConversionFailedException(final String message) {
         super(message);
     }
 
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java
new file mode 100644 (file)
index 0000000..e8e1ce3
--- /dev/null
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.vnfmadapter.rest.exceptions;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails;
+import org.onap.so.adapters.vnfmadapter.rest.EtsiSubscriptionNotificationController;
+import org.onap.so.rest.exceptions.HttpResouceNotFoundException;
+import org.onap.so.rest.exceptions.InvalidRestRequestException;
+import org.onap.so.rest.exceptions.RestProcessingException;
+import org.slf4j.Logger;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+/**
+ * Exception Handler for the Etsi Subscription Notification Controller {@link EtsiSubscriptionNotificationController
+ * EtsiSubscriptionNotificationController}
+ * 
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@ControllerAdvice(assignableTypes = EtsiSubscriptionNotificationController.class)
+public class EtsiSubscriptionNotificationControllerExceptionHandler {
+
+    private static final Logger logger = getLogger(EtsiSubscriptionNotificationControllerExceptionHandler.class);
+
+    @ExceptionHandler(InvalidRestRequestException.class)
+    public ResponseEntity<ProblemDetails> handleInvalidRestRequestException(
+            final InvalidRestRequestException invalidRestRequestException) {
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.BAD_REQUEST + ".\n" + invalidRestRequestException.getMessage();
+        logger.error(errorMessage);
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ProblemDetails().detail(errorMessage));
+    }
+
+    @ExceptionHandler(HttpResouceNotFoundException.class)
+    public ResponseEntity<ProblemDetails> handleHttpResourceNotFoundException(
+            final HttpResouceNotFoundException httpResourceNotFoundException) {
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.NOT_FOUND + ".\n" + httpResourceNotFoundException.getMessage();
+        logger.error(errorMessage);
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ProblemDetails().detail(errorMessage));
+    }
+
+    @ExceptionHandler(RestProcessingException.class)
+    public ResponseEntity<ProblemDetails> handleRestProcessingException(
+            final RestProcessingException restProcessingException) {
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + restProcessingException.getStatusCode() + ".\n" + restProcessingException.getMessage();
+        logger.error(errorMessage);
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ProblemDetails().detail(errorMessage));
+    }
+
+    @ExceptionHandler(InternalServerErrorException.class)
+    public ResponseEntity<ProblemDetails> handleInternalServerErrorException(
+            final InternalServerErrorException internalServerErrorException) {
+        logger.error(internalServerErrorException.getMessage());
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                .body(new ProblemDetails().detail(internalServerErrorException.getMessage()));
+    }
+
+    @ExceptionHandler(AuthenticationTypeNotSupportedException.class)
+    public ResponseEntity<ProblemDetails> handleAuthenticationTypeNotSupportedException(
+            final AuthenticationTypeNotSupportedException authenticationTypeNotSupportedException) {
+        logger.error(authenticationTypeNotSupportedException.getMessage());
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                .body(new ProblemDetails().detail(authenticationTypeNotSupportedException.getMessage()));
+    }
+
+    @ExceptionHandler(ConversionFailedException.class)
+    public ResponseEntity<ProblemDetails> handleConversionFailedException(
+            final ConversionFailedException conversionFailedException) {
+        logger.error(conversionFailedException.getMessage());
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                .body(new ProblemDetails().detail(conversionFailedException.getMessage()));
+    }
+
+    @ExceptionHandler(NotificationTypeNotSupportedException.class)
+    public ResponseEntity<ProblemDetails> handleNotificationTypeNotSupportedException(
+            final NotificationTypeNotSupportedException notificationTypeNotSupportedException) {
+        logger.error(notificationTypeNotSupportedException.getMessage());
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                .body(new ProblemDetails().detail(notificationTypeNotSupportedException.getMessage()));
+    }
+
+    @ExceptionHandler(SubscriptionNotFoundException.class)
+    public ResponseEntity<ProblemDetails> handleSubscriptionNotFoundException(
+            final SubscriptionNotFoundException subscriptionNotFoundException) {
+        logger.error(subscriptionNotFoundException.getMessage());
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                .body(new ProblemDetails().detail(subscriptionNotFoundException.getMessage()));
+    }
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java
new file mode 100644 (file)
index 0000000..dcc9886
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.adapters.vnfmadapter.rest.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Exception for an unsupported notification type
+ * 
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
+public class NotificationTypeNotSupportedException extends RuntimeException {
+
+    private static final long serialVersionUID = 2939423208362066902L;
+
+    public NotificationTypeNotSupportedException(final String message) {
+        super(message);
+    }
+
+    @Override
+    public synchronized Throwable fillInStackTrace() {
+        return this;
+    }
+
+}
index da8b0cb..8091f35 100644 (file)
@@ -22,10 +22,6 @@ package org.onap.so.adapters.vnfmadapter.rest.exceptions;
 
 import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails;
 import org.onap.so.adapters.vnfmadapter.rest.Sol003PackageManagementController;
-import org.onap.so.adapters.vnfmadapter.rest.exceptions.EtsiCatalogManagerRequestFailureException;
-import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgBadRequestException;
-import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgConflictException;
-import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgNotFoundException;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.ControllerAdvice;
@@ -64,11 +60,11 @@ public class Sol003PackageManagementControllerExceptionHandler {
         return ResponseEntity.status(HttpStatus.NOT_FOUND).body(problemDetails);
     }
 
-    @ExceptionHandler(SubscriptionRequestConversionException.class)
-    public ResponseEntity<ProblemDetails> handleSubscriptionRequestConversionException(
-            final SubscriptionRequestConversionException subscriptionRequestConversionException) {
+    @ExceptionHandler(ConversionFailedException.class)
+    public ResponseEntity<ProblemDetails> handleConversionFailedException(
+            final ConversionFailedException conversionFailedException) {
         final ProblemDetails problemDetails = new ProblemDetails();
-        problemDetails.setDetail(subscriptionRequestConversionException.getMessage());
+        problemDetails.setDetail(conversionFailedException.getMessage());
         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(problemDetails);
     }
 
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java
new file mode 100644 (file)
index 0000000..8012f7e
--- /dev/null
@@ -0,0 +1,592 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.vnfmadapter.rest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onap.so.adapters.vnfmadapter.Constants.ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL;
+import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.so.adapters.vnfmadapter.Constants;
+import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.NOTIFICATIONLINKSERIALIZER;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgmLinks;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthenticationParamsBasic;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthenticationParamsOauth2ClientCredentials;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageChangeNotification;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageOnboardingNotification;
+import org.onap.so.configuration.rest.BasicHttpHeadersProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.http.*;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.client.MockRestServiceServer;
+import org.springframework.web.client.RestTemplate;
+import org.threeten.bp.LocalDateTime;
+import org.threeten.bp.OffsetDateTime;
+import org.threeten.bp.ZoneOffset;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = VnfmAdapterApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+public class EtsiSubscriptionNotificationControllerTest {
+
+    @LocalServerPort
+    private int port;
+
+    private static final URI CALLBACK_URI = URI.create("http://test_callback_uri/notification");
+    private static final String TOKEN_ENDPOINT = "http://test_token_endpoint_uri/";
+    private static final String TOKEN = "dXNlcm5hbWU6cGFzc3dvcmQ=......";
+    private static final String JSON_TOKEN = "{\"access_token\":\"" + TOKEN + "\"}";
+    private static final String LOCALHOST_URL = "http://localhost:";
+    private static final String NOTIFICATION_BASE_URL =
+            ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL + "/notification";
+    private static final String USERNAME = "username";
+    private static final String PASSWORD = "password";
+    private static final String EXPECTED_BASIC_AUTHORIZATION = "Basic dXNlcm5hbWU6cGFzc3dvcmQ=";
+    private static final String EXPECTED_OAUTH_AUTHORIZATION = "Bearer " + TOKEN;
+    private static final String NOTIFICATION_ID = "NOTIFICATION_ID";
+    private static final String SUBSCRIPTION_ID = "SUBSCRIPTION_ID";
+    private static final OffsetDateTime TIMESTAMP =
+            OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 1, 1, 1, 1), ZoneOffset.ofHours(1));
+    private static final String VNFPKG_ID = UUID.randomUUID().toString();
+    private static final String VNFD_ID = UUID.randomUUID().toString();
+
+    private BasicHttpHeadersProvider basicHttpHeadersProvider;
+    private final Gson gson = new GsonBuilder().create();;
+
+    @Autowired
+    @Qualifier(CONFIGURABLE_REST_TEMPLATE)
+    private RestTemplate restTemplate;
+    private MockRestServiceServer mockRestServer;
+
+    @Autowired
+    private TestRestTemplate testRestTemplate;
+
+    @Autowired
+    private CacheManager cacheServiceProvider;
+    private Cache cache;
+
+    @Before
+    public void setUp() {
+        mockRestServer = MockRestServiceServer.bindTo(restTemplate).build();
+        basicHttpHeadersProvider = new BasicHttpHeadersProvider();
+        cache = cacheServiceProvider.getCache(Constants.PACKAGE_MANAGEMENT_SUBSCRIPTION_CACHE);
+        cache.clear();
+    }
+
+    @After
+    public void tearDown() {
+        cache.clear();
+    }
+
+    @Test
+    public void testSubscriptionNotificationEndPoint_ReturnsNoContent() {
+        final ResponseEntity<?> response = sendHttpGet(NOTIFICATION_BASE_URL);
+        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
+    }
+
+    @Test
+    public void testOnboardingNotificationSentOnToVnfmCallbackUri_SubscriptionRequestInCache_Success() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andExpect(jsonPath("$.id").value(NOTIFICATION_ID))
+                .andExpect(jsonPath("$.notificationType")
+                        .value(VnfPackageOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION
+                                .toString()))
+                .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID))
+                .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString()))
+                .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString()))
+                .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString()))
+                .andExpect(jsonPath("$._links").value(buildPkgmLinks()))
+                .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess());
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
+    }
+
+    @Test
+    public void testOnboardingNotificationNotSentOnToVnfmCallbackUri_SubscriptionRequestNotInCache_Fail() {
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "No subscription found with subscriptionId " + SUBSCRIPTION_ID
+                + ". Unable to forward notification to subscriber.";
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testOnboardingNotificationSentOnToVnfmCallbackUri_BadRequestResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.BAD_REQUEST));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.BAD_REQUEST + ".\n" + "No result found for given url: " + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testOnboardingNotificationSentOnToVnfmCallbackUri_301MovedPermanentlyResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.MOVED_PERMANENTLY));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed.";
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testOnboardingNotificationSentOnToVnfmCallbackUri_NotFoundResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.NOT_FOUND));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.NOT_FOUND + ".\n" + "No result found for given url: " + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testOnboardingNotificationSentOnToVnfmCallbackUri_InternalServerErrorResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.INTERNAL_SERVER_ERROR.value() + ".\n" + "Unable to invoke HTTP POST using URL: "
+                + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testChangeNotificationSentOnToVnfmCallbackUri_SubscriptionRequestInCache_Success() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andExpect(jsonPath("$.id").value(NOTIFICATION_ID))
+                .andExpect(jsonPath("$.notificationType").value(
+                        VnfPackageChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION.toString()))
+                .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID))
+                .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString()))
+                .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString()))
+                .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString()))
+                .andExpect(
+                        jsonPath("$.changeType").value(PkgChangeNotification.ChangeTypeEnum.OP_STATE_CHANGE.toString()))
+                .andExpect(jsonPath("$.operationalState")
+                        .value(PkgChangeNotification.OperationalStateEnum.ENABLED.toString()))
+                .andExpect(jsonPath("$._links").value(buildPkgmLinks()))
+                .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess());
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
+    }
+
+    @Test
+    public void testChangeNotificationNotSentOnToVnfmCallbackUri_SubscriptionRequestNotInCache_Fail() {
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "No subscription found with subscriptionId " + SUBSCRIPTION_ID
+                + ". Unable to forward notification to subscriber.";
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testChangeNotificationSentOnToVnfmCallbackUri_BadRequestResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.BAD_REQUEST));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.BAD_REQUEST + ".\n" + "No result found for given url: " + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testChangeNotificationSentOnToVnfmCallbackUri_NotFoundResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.NOT_FOUND));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.NOT_FOUND + ".\n" + "No result found for given url: " + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testChangeNotificationSentOnToVnfmCallbackUri_InternalServerErrorResponseFromCallbackUri_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.INTERNAL_SERVER_ERROR.value() + ".\n" + "Unable to invoke HTTP POST using URL: "
+                + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testNotificationSentOnToVnfm_BasicAuthUserPasswordAuthorized_Success() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgOnboardingNotification notification = buildPkgOnboardingNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andExpect(jsonPath("$.id").value(NOTIFICATION_ID))
+                .andExpect(jsonPath("$.notificationType")
+                        .value(VnfPackageOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION
+                                .toString()))
+                .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID))
+                .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString()))
+                .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString()))
+                .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString()))
+                .andExpect(jsonPath("$._links").value(buildPkgmLinks()))
+                .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess());
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
+    }
+
+    @Test
+    public void testNotificationSentOnToVnfm_BasicAuthUserPasswordNotAuthorized_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION))
+                .andRespond(withStatus(HttpStatus.UNAUTHORIZED));
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Sending of notification to VNFM failed with response: "
+                + HttpStatus.UNAUTHORIZED.value() + ".\n" + "Unable to invoke HTTP POST using URL: " + CALLBACK_URI;
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testNotificationSentOnToVnfm_OAuthAuthorized_Success() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(TOKEN_ENDPOINT)).andExpect(method(HttpMethod.POST))
+                .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION))
+                .andRespond(withSuccess(JSON_TOKEN, MediaType.APPLICATION_JSON));
+
+        mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST))
+                .andExpect(header("Authorization", EXPECTED_OAUTH_AUTHORIZATION))
+                .andExpect(jsonPath("$.id").value(NOTIFICATION_ID))
+                .andExpect(jsonPath("$.notificationType").value(
+                        VnfPackageChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION.toString()))
+                .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID))
+                .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString()))
+                .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString()))
+                .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString()))
+                .andExpect(
+                        jsonPath("$.changeType").value(PkgChangeNotification.ChangeTypeEnum.OP_STATE_CHANGE.toString()))
+                .andExpect(jsonPath("$.operationalState")
+                        .value(PkgChangeNotification.OperationalStateEnum.ENABLED.toString()))
+                .andExpect(jsonPath("$._links").value(buildPkgmLinks())).andRespond(withSuccess());
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
+    }
+
+    @Test
+    public void testNotificationSentOnToVnfm_OAuthTokenNotReceived_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        mockRestServer.expect(requestTo(TOKEN_ENDPOINT)).andExpect(method(HttpMethod.POST))
+                .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess());
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Unable to retrieve OAuth Token from VNFM for notification.";
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    @Test
+    public void testNotificationSentOnToVnfm_TLSCertNotYetSupported_Fail() {
+        final PkgmSubscriptionRequest subscriptionRequest =
+                buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT);
+        cache.put(SUBSCRIPTION_ID, subscriptionRequest);
+        final PkgChangeNotification notification = buildPkgChangeNotification();
+        final String notificationString = gson.toJson(notification);
+
+        final ResponseEntity<?> response = sendHttpPost(notificationString);
+
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertTrue(response.getBody() instanceof ProblemDetails);
+
+        final ProblemDetails problemDetails = (ProblemDetails) response.getBody();
+        final String errorMessage = "An error occurred.  Authentication type "
+                + subscriptionRequest.getAuthentication().getAuthType().toString() + " not currently supported.";
+
+        assertEquals(errorMessage, problemDetails.getDetail());
+    }
+
+    private PkgOnboardingNotification buildPkgOnboardingNotification() {
+        final PkgOnboardingNotification notification = new PkgOnboardingNotification();
+        notification.setId(NOTIFICATION_ID);
+        notification
+                .setNotificationType(PkgOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION);
+        notification.setSubscriptionId(SUBSCRIPTION_ID);
+        notification.setTimeStamp(TIMESTAMP);
+        notification.setVnfPkgId(VNFPKG_ID);
+        notification.setVnfdId(VNFD_ID);
+        notification.setLinks(buildPkgmLinks());
+        return notification;
+    }
+
+    private PkgChangeNotification buildPkgChangeNotification() {
+        final PkgChangeNotification notification = new PkgChangeNotification();
+        notification.setId(NOTIFICATION_ID);
+        notification.setNotificationType(PkgChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION);
+        notification.setSubscriptionId(SUBSCRIPTION_ID);
+        notification.setTimeStamp(TIMESTAMP);
+        notification.setVnfPkgId(VNFPKG_ID);
+        notification.setVnfdId(VNFD_ID);
+        notification.setChangeType(PkgChangeNotification.ChangeTypeEnum.OP_STATE_CHANGE);
+        notification.setOperationalState(PkgChangeNotification.OperationalStateEnum.ENABLED);
+        notification.setLinks(buildPkgmLinks());
+        return notification;
+    }
+
+    private PkgmLinks buildPkgmLinks() {
+        final PkgmLinks pkgmLinks = new PkgmLinks();
+
+        final NOTIFICATIONLINKSERIALIZER subscriptionLinkSerializer = new NOTIFICATIONLINKSERIALIZER();
+        subscriptionLinkSerializer.setHref("subscription_href");
+        pkgmLinks.setSubscription(subscriptionLinkSerializer);
+
+        final NOTIFICATIONLINKSERIALIZER vnfPackageLinkSerializer = new NOTIFICATIONLINKSERIALIZER();
+        vnfPackageLinkSerializer.setHref("vnf_package_href");
+        pkgmLinks.setVnfPackage(vnfPackageLinkSerializer);
+
+        return pkgmLinks;
+    }
+
+    private PkgmSubscriptionRequest buildPkgmSubscriptionRequest(
+            final SubscriptionsAuthentication.AuthTypeEnum authTypeEnum) {
+        final PkgmSubscriptionRequest subscriptionRequest = new PkgmSubscriptionRequest();
+        subscriptionRequest.setCallbackUri(CALLBACK_URI.toString());
+        subscriptionRequest.setAuthentication(buildSubscriptionsAuthentication(authTypeEnum));
+        return subscriptionRequest;
+    }
+
+    // TODO update for auth types other than basicAuth
+    private SubscriptionsAuthentication buildSubscriptionsAuthentication(
+            final SubscriptionsAuthentication.AuthTypeEnum authTypeEnum) {
+        final SubscriptionsAuthentication subscriptionsAuthentication = new SubscriptionsAuthentication();
+        final List<SubscriptionsAuthentication.AuthTypeEnum> authTypes = new ArrayList<>();
+        authTypes.add(authTypeEnum);
+        subscriptionsAuthentication.setAuthType(authTypes);
+        if (authTypeEnum == SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT) {
+            // TODO: remove basic params and code for TLS
+            final SubscriptionsAuthenticationParamsBasic basicParams =
+                    new SubscriptionsAuthenticationParamsBasic().userName(USERNAME).password(PASSWORD);
+            subscriptionsAuthentication.setParamsBasic(basicParams);
+        } else if (authTypeEnum == SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS) {
+            final SubscriptionsAuthenticationParamsOauth2ClientCredentials oathParams =
+                    new SubscriptionsAuthenticationParamsOauth2ClientCredentials().clientId(USERNAME)
+                            .clientPassword(PASSWORD).tokenEndpoint(TOKEN_ENDPOINT);
+            subscriptionsAuthentication.setParamsOauth2ClientCredentials(oathParams);
+        } else {
+            final SubscriptionsAuthenticationParamsBasic basicParams =
+                    new SubscriptionsAuthenticationParamsBasic().userName(USERNAME).password(PASSWORD);
+            subscriptionsAuthentication.setParamsBasic(basicParams);
+        }
+
+        return subscriptionsAuthentication;
+    }
+
+    private <T> ResponseEntity<ProblemDetails> sendHttpPost(final T notification) {
+        final String testURL = LOCALHOST_URL + port + NOTIFICATION_BASE_URL;
+        final HttpEntity<?> request = new HttpEntity<>(notification, basicHttpHeadersProvider.getHttpHeaders());
+        return testRestTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.POST, request,
+                ProblemDetails.class);
+    }
+
+    private ResponseEntity<Void> sendHttpGet(final String url) {
+        final String testURL = LOCALHOST_URL + port + url;
+        final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders());
+        return testRestTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.GET, request, Void.class);
+    }
+
+}