summaryrefslogtreecommitdiffstats
path: root/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services
diff options
context:
space:
mode:
Diffstat (limited to 'openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services')
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/CatalogNotifier.java193
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java10
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/AsyncNotifier.java101
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/EntryNotConfiguredException.java30
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/Notifier.java32
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/NotifierFactory.java105
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpConfiguration.java43
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpNotificationTask.java135
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpTaskProducer.java107
9 files changed, 559 insertions, 197 deletions
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/CatalogNotifier.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/CatalogNotifier.java
deleted file mode 100644
index deced74e3c..0000000000
--- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/CatalogNotifier.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright © 2018 European Support Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openecomp.sdcrests.item.rest.services;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.onap.sdc.tosca.services.YamlUtil;
-import org.openecomp.core.utilities.json.JsonUtil;
-import org.openecomp.sdc.common.session.SessionContextProviderFactory;
-import org.openecomp.sdc.logging.api.Logger;
-import org.openecomp.sdc.logging.api.LoggerFactory;
-import org.openecomp.sdc.logging.api.LoggingContext;
-import org.openecomp.sdcrests.item.types.ItemAction;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-
- class CatalogNotifier {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(CatalogNotifier.class);
-
- private static final String USER_ID_HEADER_PARAM = "USER_ID";
- private static final String CONFIG_FILE = "configuration.yaml";
- private static final String PROTOCOL_KEY = "beProtocol";
- private static final String HTTP_PROTOCOL = "http|HTTP";
- private static final String HTTPS_PROTOCOL = "https|HTTPS";
- private static final String HOST_KEY = "beFqdn";
- private static final String HTTP_PORT_KEY = "beHttpPort";
- private static final String HTTPS_PORT_KEY = "beSslPort";
- private static final String URL_KEY = "onboardCatalogNotificationUrl";
- private static final String URL_DEFAULT_FORMAT = "%s://%s:%s/sdc2/rest/v1/catalog/notif/vsp/";
-
- private static String configurationYamlFile = System.getProperty(CONFIG_FILE);
- private static String notifyCatalogUrl;
-
- private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
-
-
- static {
- Function<InputStream, Map<String, LinkedHashMap<String, Object>>> reader = is -> {
- YamlUtil yamlUtil = new YamlUtil();
- return yamlUtil.yamlToMap(is);
- };
-
- Map<String, LinkedHashMap<String, Object>> configurationMap;
-
- try {
- configurationMap = readFromFile(configurationYamlFile, reader);
- Object protocol = configurationMap.get(PROTOCOL_KEY);
- Object host = configurationMap.get(HOST_KEY);
-
- if (protocol == null || host == null) {
- throw new ExceptionInInitializerError("Could not read configuration file configuration.yaml.");
- }
-
- Object port = null;
- if (String.valueOf(protocol).matches(HTTP_PROTOCOL)) {
- port = configurationMap.get(HTTP_PORT_KEY);
- }
- if (String.valueOf(protocol).matches(HTTPS_PROTOCOL)) {
- port = configurationMap.get(HTTPS_PORT_KEY);
- }
-
- if (configurationMap.get(URL_KEY) != null) {
- String urlFormat = String.valueOf(configurationMap.get(URL_KEY));
- notifyCatalogUrl =
- String.format(urlFormat, String.valueOf(protocol), String.valueOf(host), String.valueOf(port));
-
- } else {
- notifyCatalogUrl = String.format(URL_DEFAULT_FORMAT, String.valueOf(protocol), String.valueOf(host),
- String.valueOf(port));
- }
-
- } catch (Exception e) {
- throw new ExceptionInInitializerError(
- "Could not read configuration file configuration.yaml. Error: " + e.getMessage());
-
- }
- }
-
-
- public void execute(Collection<String> itemIds, ItemAction action, int numOfRetries) {
-
- String userId = SessionContextProviderFactory.getInstance().createInterface().get().getUser().getUserId();
-
- Callable callable = createCallable(JsonUtil.object2Json(itemIds), action, numOfRetries, userId);
-
- executor.submit(callable);
-
- }
-
- private Callable createCallable(String itemIds, ItemAction action, int numOfRetries, String userId) {
- Callable callable = () -> handleHttpRequest(getUrl(action), itemIds, action, userId, numOfRetries);
- LoggingContext.copyToCallable(callable);
- return callable;
- }
-
- private Void handleHttpRequest(String url, String itemIds, ItemAction action, String userId,
- int numOfRetries) {
-
- try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
- HttpPost request = createPostRequest(url, itemIds, userId);
- HttpResponse response = httpclient.execute(request);
- LOGGER.debug(String.format("Catalog notification on vspId - %s action - %s. Response: %s", itemIds,
- action.name(), response.getStatusLine()));
-
- if (numOfRetries > 1 && response.getStatusLine().getStatusCode() == Response.Status.INTERNAL_SERVER_ERROR
- .getStatusCode()) {
- Callable callable =
- createCallable(getFailedIds(itemIds, response.getEntity()), action, --numOfRetries, userId);
- executor.schedule(callable, 5, TimeUnit.SECONDS);
- }
-
- } catch (Exception e) {
- LOGGER.error(String.format("Catalog notification on vspId - %s action - %s FAILED. Error: %S", itemIds,
- action.name(), e.getMessage()));
- }
- return null;
- }
-
- private String getFailedIds(String itemIds, HttpEntity responseBody) {
- try {
- Map jsonBody = JsonUtil.json2Object(responseBody.getContent(), Map.class);
- return jsonBody.get("failedIds").toString();
- } catch (Exception e) {
- LOGGER.error("Catalog Notification RETRY - no failed IDs in response");
- }
- return JsonUtil.object2Json(itemIds);
- }
-
- private HttpPost createPostRequest(String postUrl, String itemIds, String userId)
- throws UnsupportedEncodingException {
-
- HttpPost request = new HttpPost(postUrl);
-
- request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
- request.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- request.addHeader(USER_ID_HEADER_PARAM, userId);
-
- HttpEntity entity = new StringEntity(itemIds);
- request.setEntity(entity);
-
- return request;
- }
-
- private String getUrl(ItemAction action) {
- String actionStr = "";
- if (action == ItemAction.ARCHIVE) {
- actionStr = "archived";
- } else if (action == ItemAction.RESTORE) {
- actionStr = "restored";
- }
- LOGGER.debug("Catalog notification URL - " + notifyCatalogUrl + actionStr);
- return notifyCatalogUrl + actionStr;
- }
-
- private static <T> T readFromFile(String file, Function<InputStream, T> reader) throws IOException {
- try (InputStream is = new FileInputStream(file)) {
- return reader.apply(is);
- }
- }
-}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java
index b00e4594b3..a93c063220 100644
--- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java
@@ -40,6 +40,8 @@ import org.openecomp.sdc.versioning.types.ItemStatus;
import org.openecomp.sdc.versioning.types.NotificationEventTypes;
import org.openecomp.sdcrests.item.rest.Items;
import org.openecomp.sdcrests.item.rest.mapping.MapItemToDto;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.Notifier;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.NotifierFactory;
import org.openecomp.sdcrests.item.types.ItemAction;
import org.openecomp.sdcrests.item.types.ItemActionRequestDto;
import org.openecomp.sdcrests.item.types.ItemDto;
@@ -113,9 +115,9 @@ public class ItemsImpl implements Items {
actionSideAffectsMap.get(request.getAction()).execute(item, user);
try {
- CatalogNotifier catalogNotifier = new CatalogNotifier();
- catalogNotifier.execute(Collections.singleton(itemId), request.getAction(), 2);
- } catch (Exception e){
+ Notifier notifier = NotifierFactory.getInstance();
+ notifier.execute(Collections.singleton(itemId), request.getAction());
+ } catch (Exception e) {
LOGGER.error("Failed to send catalog notification on item " + itemId + " Error: " + e.getMessage());
}
@@ -323,6 +325,6 @@ public class ItemsImpl implements Items {
//Do not delete - is in use, duplicates code to prevent dependency on openecomp-sdc-vendor-software-product-api
private enum OnboardingMethod {
- NetworkPackage, Manual;
+ NetworkPackage, Manual
}
} \ No newline at end of file
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/AsyncNotifier.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/AsyncNotifier.java
new file mode 100644
index 0000000000..82880106d7
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/AsyncNotifier.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification;
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiFunction;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdc.logging.api.LoggingContext;
+import org.openecomp.sdcrests.item.types.ItemAction;
+
+/**
+ * Asynchronously runs a notification task.
+ *
+ * @author evitaliy
+ * @since 22 Nov 2018
+ */
+public class AsyncNotifier implements Notifier {
+
+ private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(1);
+
+ private static final int DEFAULT_NUM_OF_RETRIES = 2;
+ private static final long DEFAULT_INTERVAL = 5000;
+
+ private final BiFunction<Collection<String>, ItemAction, Callable<NextAction>> taskProducer;
+
+ AsyncNotifier(BiFunction<Collection<String>, ItemAction, Callable<NextAction>> taskProducer) {
+ this.taskProducer = taskProducer;
+ }
+
+ @Override
+ public void execute(Collection<String> itemIds, ItemAction action) {
+
+ Callable<AsyncNotifier.NextAction> worker = taskProducer.apply(itemIds, action);
+
+ RetryingTask retryingTask =
+ new RetryingTask(worker, DEFAULT_NUM_OF_RETRIES, DEFAULT_INTERVAL, EXECUTOR_SERVICE);
+
+ EXECUTOR_SERVICE.submit(LoggingContext.copyToCallable(retryingTask));
+ }
+
+ public enum NextAction {
+ RETRY, DONE
+ }
+
+ static class RetryingTask implements Callable<Void> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RetryingTask.class);
+
+ private final Callable<AsyncNotifier.NextAction> worker;
+ private final long delay;
+ private final ScheduledExecutorService scheduler;
+ private volatile int retries;
+
+ RetryingTask(Callable<AsyncNotifier.NextAction> worker, int numOfRetries, long delay,
+ ScheduledExecutorService scheduler) {
+
+ this.worker = worker;
+ this.retries = numOfRetries;
+ this.delay = delay;
+ this.scheduler = scheduler;
+ }
+
+ @Override
+ public synchronized Void call() throws Exception {
+
+ NextAction next = worker.call();
+ if (next == NextAction.DONE) {
+ LOGGER.debug("Task successful: {}. Not going to retry", worker);
+ return null;
+ }
+
+ retries--;
+ if (retries == 0) {
+ LOGGER.warn("Exhausted number of retries for task {}, exiting", worker);
+ return null;
+ }
+
+ scheduler.schedule(this, delay, TimeUnit.MILLISECONDS);
+ return null;
+ }
+ }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/EntryNotConfiguredException.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/EntryNotConfiguredException.java
new file mode 100644
index 0000000000..070164afe6
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/EntryNotConfiguredException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification;
+
+/**
+ * Thrown when an expected entry was not found in configuration.
+ *
+ * @author evitaliy
+ * @since 21 Nov 2018
+ */
+public class EntryNotConfiguredException extends RuntimeException {
+
+ public EntryNotConfiguredException(String configEntry) {
+ super(configEntry + " must be configured");
+ }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/Notifier.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/Notifier.java
new file mode 100644
index 0000000000..9143de4212
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/Notifier.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification;
+
+import java.util.Collection;
+import org.openecomp.sdcrests.item.types.ItemAction;
+
+/**
+ * Notifies the Catalog of an action being performed on items referenced by their IDs.
+ *
+ * @author evitaliy
+ * @since 21 Nov 2018
+ */
+@FunctionalInterface
+public interface Notifier {
+
+ void execute(Collection<String> itemIds, ItemAction action);
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/NotifierFactory.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/NotifierFactory.java
new file mode 100644
index 0000000000..a7f1e9c7fb
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/NotifierFactory.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import org.onap.sdc.tosca.services.YamlUtil;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.http.HttpConfiguration;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.http.HttpTaskProducer;
+import org.openecomp.sdcrests.item.types.ItemAction;
+
+/**
+ * Creates an instance of {@link Notifier}, initialized according to current configuration.
+ * The configuration must be passed via the {@link #CONFIG_FILE_PROPERTY} JVM argument.
+ */
+public class NotifierFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NotifierFactory.class);
+
+ private static final String CONFIG_FILE_PROPERTY = "configuration.yaml";
+ private static final String CONFIG_SECTION = "catalogNotificationsConfig";
+
+ private static final Notifier INSTANCE;
+
+ static {
+ INSTANCE = createInstance();
+ }
+
+ /**
+ * Returns a {@link Notifier} instance according to the provided configuration. If no configuration was not
+ * provided, or the given configuration is incorrect, then an instance with reduced functionality will be returned.
+ *
+ * @return available instance of {@link Notifier}
+ */
+ public static Notifier getInstance() {
+ return INSTANCE;
+ }
+
+ static Notifier createInstance() {
+
+ try {
+
+ String file = Objects.requireNonNull(System.getProperty(CONFIG_FILE_PROPERTY),
+ "Config file location must be specified via system property " + CONFIG_FILE_PROPERTY);
+
+ Object config = getNotificationConfiguration(file);
+ ObjectMapper mapper = new ObjectMapper();
+ HttpConfiguration httpConfig = mapper.convertValue(config, HttpConfiguration.class);
+
+ return new AsyncNotifier(new HttpTaskProducer(httpConfig));
+
+ } catch (Exception e) {
+ LOGGER.warn("Failed to initialize notifier. Notifications will not be sent", e);
+ return new UnsupportedConfigurationNotifier();
+ }
+ }
+
+ private static Object getNotificationConfiguration(String file) throws IOException {
+
+ Map<?, ?> configuration = Objects.requireNonNull(readConfigurationFile(file), "Configuration cannot be empty");
+ Object notificationConfig = configuration.get(CONFIG_SECTION);
+ if (notificationConfig == null) {
+ throw new EntryNotConfiguredException(CONFIG_SECTION + " section");
+ }
+
+ return notificationConfig;
+ }
+
+ private static Map<?, ?> readConfigurationFile(String file) throws IOException {
+
+ try (InputStream fileInput = new FileInputStream(file)) {
+ YamlUtil yamlUtil = new YamlUtil();
+ return yamlUtil.yamlToMap(fileInput);
+ }
+ }
+
+ static class UnsupportedConfigurationNotifier implements Notifier {
+
+ @Override
+ public void execute(Collection<String> itemIds, ItemAction action) {
+ throw new IllegalStateException("Cannot send notifications. The notifier was not properly initialized");
+ }
+ }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpConfiguration.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpConfiguration.java
new file mode 100644
index 0000000000..4403bd840b
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpConfiguration.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification.http;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * Represents configuration for sending notifications to the Catalog side.
+ *
+ * @author evitaliy
+ * @since 21 Nov 2018
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+public class HttpConfiguration {
+
+ private String catalogBeProtocol;
+ private String catalogBeHttpPort;
+ private String catalogBeSslPort;
+ private String catalogBeFqdn;
+ private String catalogNotificationUrl;
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpNotificationTask.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpNotificationTask.java
new file mode 100644
index 0000000000..c88ac4ecce
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpNotificationTask.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification.http;
+
+import static org.openecomp.sdcrests.item.rest.services.catalog.notification.AsyncNotifier.NextAction.DONE;
+import static org.openecomp.sdcrests.item.rest.services.catalog.notification.AsyncNotifier.NextAction.RETRY;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.openecomp.core.utilities.json.JsonUtil;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.AsyncNotifier;
+
+/**
+ * HTTP client for notifying the Catalog of an action on items. The items are referenced by their IDs. The client can
+ * run multiple times, in which case only failed IDs will be re-attempted.
+ *
+ * @author evitaliy
+ * @since 21 Nov 2018
+ */
+@ToString
+class HttpNotificationTask implements Callable<AsyncNotifier.NextAction> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HttpNotificationTask.class);
+
+ private static final String APPLICATION_JSON = ContentType.APPLICATION_JSON.getMimeType();
+ private static final String USER_ID_HEADER_PARAM = "USER_ID";
+
+ private final String endpoint;
+ private final String userId;
+ private volatile Collection<String> itemIds;
+
+ HttpNotificationTask(String endpoint, String userId, Collection<String> itemIds) {
+ this.endpoint = endpoint;
+ this.userId = userId;
+ this.itemIds = itemIds;
+ }
+
+ @Override
+ public synchronized AsyncNotifier.NextAction call() {
+
+ try (CloseableHttpClient client = HttpClients.createDefault()) {
+
+ HttpPost request = createPostRequest(endpoint, itemIds, userId);
+
+ try (CloseableHttpResponse response = client.execute(request)) {
+
+ StatusLine status = response.getStatusLine();
+
+ LOGGER.debug("Catalog notification on VSP IDs: {}, endpoint: {}, response: {}",
+ itemIds, endpoint, status);
+
+ itemIds = getFailedIds(itemIds, response.getEntity());
+
+ if ((status.getStatusCode() == HttpStatus.SC_INTERNAL_SERVER_ERROR)
+ && (itemIds != null) && !itemIds.isEmpty()) {
+
+ LOGGER.debug("Catalog notification on VSP IDs {} failed. Endpoint: {}. Retry", itemIds, endpoint);
+ return RETRY;
+ }
+
+ return DONE;
+ }
+
+ } catch (Exception e) {
+ LOGGER.error("Catalog notification on VSP IDs {} failed. Endpoint: {}", itemIds, endpoint, e);
+ return DONE;
+ }
+ }
+
+ private HttpPost createPostRequest(String postUrl, Collection<String> itemIds, String userId)
+ throws UnsupportedEncodingException {
+
+ HttpPost request = new HttpPost(postUrl);
+
+ request.addHeader(HttpHeaders.ACCEPT, APPLICATION_JSON);
+ request.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON);
+ request.addHeader(USER_ID_HEADER_PARAM, userId);
+
+ HttpEntity entity = new StringEntity(JsonUtil.object2Json(itemIds));
+ request.setEntity(entity);
+ return request;
+ }
+
+ private Collection<String> getFailedIds(Collection<String> itemIds, HttpEntity responseBody) {
+
+ try {
+ NotificationResponse response = JsonUtil.json2Object(responseBody.getContent(), NotificationResponse.class);
+ return response != null ? response.failedIds : null;
+ } catch (Exception e) {
+ LOGGER.error("Error getting failed IDs from response", e);
+ }
+
+ return itemIds;
+ }
+
+ @Setter
+ @Getter
+ @ToString
+ @NoArgsConstructor
+ private static class NotificationResponse {
+
+ private Collection<String> failedIds;
+ }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpTaskProducer.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpTaskProducer.java
new file mode 100644
index 0000000000..c6abd346ff
--- /dev/null
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/catalog/notification/http/HttpTaskProducer.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.item.rest.services.catalog.notification.http;
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import java.util.function.BiFunction;
+import org.openecomp.sdc.common.session.SessionContextProviderFactory;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.AsyncNotifier;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.EntryNotConfiguredException;
+import org.openecomp.sdcrests.item.rest.services.catalog.notification.Notifier;
+import org.openecomp.sdcrests.item.types.ItemAction;
+
+/**
+ * Notifies the Catalog via an HTTP.
+ *
+ * @author evitaliy
+ * @since 21 Nov 2018
+ */
+public class HttpTaskProducer
+ implements BiFunction<Collection<String>, ItemAction, Callable<AsyncNotifier.NextAction>>, Notifier {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HttpTaskProducer.class);
+
+ private static final String CATALOG_HTTP_PROTOCOL = "HTTP";
+ private static final String CATALOG_HTTPS_PROTOCOL = "HTTPS";
+
+ private final String notifyCatalogUrl;
+
+ /**
+ * Initializes the producer from a provided configuration.
+ *
+ * @param config HTTP-specific configuration, cannot be null
+ */
+ public HttpTaskProducer(HttpConfiguration config) {
+ String protocol = ensureEntryConfigured(config.getCatalogBeProtocol(), "Protocol");
+ String host = ensureEntryConfigured(config.getCatalogBeFqdn(), "Catalog host");
+ String url = ensureEntryConfigured(config.getCatalogNotificationUrl(), "Notification URL");
+ String port = getPortConfiguration(protocol, config);
+ this.notifyCatalogUrl = String.format(url, protocol, host, port);
+ }
+
+ private static String ensureEntryConfigured(String value, String entryName) {
+
+ if (value == null) {
+ throw new EntryNotConfiguredException(entryName);
+ }
+
+ return value;
+ }
+
+ private static String getPortConfiguration(String protocol, HttpConfiguration config) {
+
+ if (CATALOG_HTTP_PROTOCOL.equalsIgnoreCase(protocol)) {
+ return ensureEntryConfigured(config.getCatalogBeHttpPort(), "HTTP port");
+ } else if (CATALOG_HTTPS_PROTOCOL.equalsIgnoreCase(protocol)) {
+ return ensureEntryConfigured(config.getCatalogBeSslPort(), "SSL port");
+ } else {
+ throw new IllegalArgumentException("Unsupported protocol: " + protocol);
+ }
+ }
+
+ @Override
+ public Callable<AsyncNotifier.NextAction> apply(Collection<String> itemIds, ItemAction action) {
+ return createNotificationTask(itemIds, action);
+ }
+
+ private static String getEndpoint(ItemAction action) {
+
+ if (action == ItemAction.ARCHIVE) {
+ return "archived";
+ } else if (action == ItemAction.RESTORE) {
+ return "restored";
+ } else {
+ throw new IllegalArgumentException("Unsupported action: " + action.name());
+ }
+ }
+
+ @Override
+ public void execute(Collection<String> itemIds, ItemAction action) {
+ HttpNotificationTask task = createNotificationTask(itemIds, action);
+ task.call();
+ }
+
+ private HttpNotificationTask createNotificationTask(Collection<String> itemIds, ItemAction action) {
+ String userId = SessionContextProviderFactory.getInstance().createInterface().get().getUser().getUserId();
+ String notificationEndpoint = notifyCatalogUrl + getEndpoint(action);
+ LOGGER.debug("Catalog notification URL: " + notificationEndpoint);
+ return new HttpNotificationTask(notificationEndpoint, userId, itemIds);
+ }
+}