From 0c51c0f629767d17c364229e5d528c8b609334da Mon Sep 17 00:00:00 2001 From: ayalaben Date: Tue, 24 Apr 2018 15:57:52 +0300 Subject: [PATCH] notify catalog on items action Change-Id: I3be022809b83ec939eaa0a383fa9e7b659dc096b Issue-ID: SDC-1257 Signed-off-by: ayalaben --- .../item-rest/item-rest-services/pom.xml | 5 + .../item/rest/services/CatalogNotifier.java | 180 +++++++++++++++++++++ .../sdcrests/item/rest/services/ItemsImpl.java | 13 +- 3 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/CatalogNotifier.java diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/pom.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/pom.xml index 6b96a4d328..5eb4b4e3da 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/pom.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/pom.xml @@ -28,6 +28,11 @@ openecomp-sdc-common-rest ${project.version} + + org.apache.httpcomponents + httpclient + ${http.client.version} + javax.inject javax.inject 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 new file mode 100644 index 0000000000..48a4f9c3b6 --- /dev/null +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/CatalogNotifier.java @@ -0,0 +1,180 @@ +/* + * 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 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; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +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; + +public 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 HOST_KEY = "beFqdn"; + private static final String PORT_KEY = "beHttpPort"; + 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>> reader = is -> { + YamlUtil yamlUtil = new YamlUtil(); + return yamlUtil.yamlToMap(is); + }; + + Map> configurationMap; + + try { + configurationMap = readFromFile(configurationYamlFile, reader); + + } catch (IOException e) { + throw new RuntimeException("Could not read configuration file configuration.yaml"); + } + + Object protocol = configurationMap.get(PROTOCOL_KEY); + Object host = configurationMap.get(HOST_KEY); + Object port = configurationMap.get(PORT_KEY); + + if (protocol == null || host == null || port == null) { + throw new RuntimeException("Could not read configuration file configuration.yaml"); + } + + 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)); + } + } + + + public void execute(Collection 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.error( + String.format("Catalog notification on vspId - %s action - %s. Response: %s", itemIds, + action.name(), response.getStatusLine())); + + if (numOfRetries > 1 && response.getStatusLine().getStatusCode() == 500) { + 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.toString(), 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.error("Catalog notification on URL - " + notifyCatalogUrl + actionStr); + return notifyCatalogUrl + actionStr; + } + + private static T readFromFile(String file, Function 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 ae6e24bb65..359662ad33 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 @@ -21,7 +21,7 @@ import static org.openecomp.sdc.versioning.VersioningNotificationConstansts.ITEM import static org.openecomp.sdc.versioning.VersioningNotificationConstansts.ITEM_NAME; import java.util.Arrays; -import java.util.Collection; +import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; @@ -66,6 +66,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; + @Named @Service("items") @Scope(value = "prototype") @@ -85,6 +86,8 @@ public class ItemsImpl implements Items { private NotificationPropagationManager notifier = NotificationPropagationManagerFactory.getInstance().createInterface(); + private CatalogNotifier catalogNotifier = new CatalogNotifier(); + private Map actionSideAffectsMap = new EnumMap<>(ItemAction.class); @PostConstruct @@ -97,6 +100,7 @@ public class ItemsImpl implements Items { private static final String ONBOARDING_METHOD = "onboardingMethod"; + @Override public Response actOn(ItemActionRequestDto request, String itemId, String user) { @@ -116,6 +120,7 @@ public class ItemsImpl implements Items { } actionSideAffectsMap.get(request.getAction()).execute(item, user); + catalogNotifier.execute(Collections.singleton(itemId),request.getAction(),2); return Response.ok().build(); } @@ -131,8 +136,8 @@ public class ItemsImpl implements Items { GenericCollectionWrapper results = new GenericCollectionWrapper<>(); MapItemToDto mapper = new MapItemToDto(); itemManager.list(itemPredicate).stream() - .sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) - .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class))); + .sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) + .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class))); return Response.ok(results).build(); @@ -323,4 +328,4 @@ public class ItemsImpl implements Items { private enum OnboardingMethod { NetworkPackage, Manual; } -} +} \ No newline at end of file -- 2.16.6