diff options
author | Michael Lando <ml636r@att.com> | 2017-02-19 10:28:42 +0200 |
---|---|---|
committer | Michael Lando <ml636r@att.com> | 2017-02-19 10:51:01 +0200 |
commit | 451a3400b76511393c62a444f588a4ed15f4a549 (patch) | |
tree | e4f5873a863d1d3e55618eab48b83262f874719d /catalog-be/src/main/java/org | |
parent | 5abfe4e1fb5fae4bbd5fbc340519f52075aff3ff (diff) |
Initial OpenECOMP SDC commit
Change-Id: I0924d5a6ae9cdc161ae17c68d3689a30d10f407b
Signed-off-by: Michael Lando <ml636r@att.com>
Diffstat (limited to 'catalog-be/src/main/java/org')
209 files changed, 54800 insertions, 0 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/api/IAuditingManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/api/IAuditingManager.java new file mode 100644 index 0000000000..36b79c2d9c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/api/IAuditingManager.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.auditing.api; + +import java.util.EnumMap; + +import javax.servlet.ServletContext; + +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; + +public interface IAuditingManager { + void auditEvent(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields); +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingLogFormatConstants.java b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingLogFormatConstants.java new file mode 100644 index 0000000000..eb14b5afe7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingLogFormatConstants.java @@ -0,0 +1,258 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.auditing.impl; + +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; + +public interface AuditingLogFormatConstants { + + static AuditingFieldsKeysEnum[] DISTRIBUTION_REGISTRATION_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_API_KEY, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_NOTIFICATION_TOPIC_NAME, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TOPIC_NAME}; + + static AuditingFieldsKeysEnum[] DISTRIBUTION_DOWNLOAD_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] GET_UEB_CLUSTER_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TIME, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_DESC + }; + + static AuditingFieldsKeysEnum[] DISTRIBUTION_DEPLOY_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] DISTRIBUTION_STATUS_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TOPIC_NAME, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TIME, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] DISTRIBUTION_NOTIFY_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] ADD_REMOVE_TOPIC_KEY_ACL_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ROLE, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_API_KEY, + AuditingFieldsKeysEnum.AUDIT_STATUS + }; + + static AuditingFieldsKeysEnum[] CREATE_TOPIC_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, + AuditingFieldsKeysEnum.AUDIT_STATUS + }; + + static AuditingFieldsKeysEnum[] ACTIVATE_DISTRIBUTION_ARRAY ={ + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_DPREV_STATUS, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_DCURR_STATUS, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] CHANGE_DISTRIBUTION_STATUS_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_DPREV_STATUS, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_DCURR_STATUS, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT + }; + + static AuditingFieldsKeysEnum[] CREATE_RESOURCE_TEMPLATE_SUFFIX_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] CREATE_RESOURCE_TEMPLATE_PREFIX_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, + AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE + }; + + static AuditingFieldsKeysEnum[] USER_ACCESS_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_USER_UID, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] USER_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_USER_UID, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] AUTH_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_AUTH_URL, + AuditingFieldsKeysEnum.AUDIT_AUTH_USER, + AuditingFieldsKeysEnum.AUDIT_AUTH_STATUS, + AuditingFieldsKeysEnum.AUDIT_AUTH_REALM + }; + + static AuditingFieldsKeysEnum[] ECOMP_USER_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_ECOMP_USER, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] CATEGORY_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_CATEGORY_NAME, + AuditingFieldsKeysEnum.AUDIT_SUB_CATEGORY_NAME, + AuditingFieldsKeysEnum.AUDIT_GROUPING_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] GET_USERS_LIST_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_USER_DETAILS, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + + static AuditingFieldsKeysEnum[] GET_CATEGORY_HIERARCHY_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_DETAILS, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + static AuditingFieldsKeysEnum[] USER_ADMIN_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_USER_BEFORE, + AuditingFieldsKeysEnum.AUDIT_USER_AFTER, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + static AuditingFieldsKeysEnum[] EXTERNAL_GET_ASSET_LIST_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + static AuditingFieldsKeysEnum[] EXTERNAL_GET_ASSET_TEMPLATE_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + static AuditingFieldsKeysEnum[] EXTERNAL_DOWNLOAD_ARTIFACT_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; + static AuditingFieldsKeysEnum[] EXTERNAL_CRUD_API_ARTIFACT_ARRAY = { + AuditingFieldsKeysEnum.AUDIT_ACTION, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, + AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, + AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, + AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, + AuditingFieldsKeysEnum.AUDIT_PREV_ARTIFACT_UUID, + AuditingFieldsKeysEnum.AUDIT_CURR_ARTIFACT_UUID, + AuditingFieldsKeysEnum.AUDIT_ARTIFACT_DATA, + AuditingFieldsKeysEnum.AUDIT_STATUS, + AuditingFieldsKeysEnum.AUDIT_DESC + }; +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingLogFormatUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingLogFormatUtil.java new file mode 100644 index 0000000000..5fec39bbdb --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingLogFormatUtil.java @@ -0,0 +1,268 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.auditing.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Formatter; +import java.util.Locale; + +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +public class AuditingLogFormatUtil { + + // When adding any new fields here, please keep the convention <fieldName>= + // <value>, with the space between them. + private static Logger log = LoggerFactory.getLogger(AuditingLogFormatUtil.class.getName()); + + // This is the key by which audit marker is recognized in logback.xml + private static String AUDIT_MARKER_STR = "AUDIT_MARKER"; + + public static Marker auditMarker = MarkerFactory.getMarker(AUDIT_MARKER_STR); + + protected static void logAuditEvent(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + + StringBuilder sb = new StringBuilder(); + Formatter formatter = new Formatter(sb, Locale.US); + log.trace("logAuditEvent - start"); + + try { + + // Common fields + String modifier = getModifier((String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME), (String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID)); + Object statusObj = auditingFields.get(AuditingFieldsKeysEnum.AUDIT_STATUS); + String status = null; + if (statusObj != null) { + status = String.valueOf(statusObj); + } + String desc = (String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_DESC); + String action = (String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_ACTION); + + AuditingActionEnum auditEventType = AuditingActionEnum.getActionByName(action); + StringBuilder formattedEvent = getFormattedEvent(auditingFields, modifier, status, desc, action, auditEventType); + String formattedString = formattedEvent.toString(); + + // This is the only way to fix DE166225 without major refactoring, + // after it was previously agreed with Ella that activity type will + // be the method name. + + if (auditEventType.equals(AuditingActionEnum.AUTH_REQUEST)) { + HttpRequestAuthentication(formattedString); + } else { + log.info(auditMarker, formattedString); + } + } catch (Exception e) { + log.debug("unexpected error occurred: {} {}", e.getMessage(), e); + + } finally { + formatter.close(); + log.trace("logAuditEvent - end"); + } + + } + + private static void HttpRequestAuthentication(String formattedString) { + log.info(auditMarker, formattedString); + } + + private static StringBuilder getFormattedEvent(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields, String modifier, String status, String desc, String action, AuditingActionEnum auditEventType) { + + StringBuilder formattedString = new StringBuilder(); + + switch (auditEventType) { + case ADD_USER: + case DELETE_USER: + case UPDATE_USER: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.USER_ADMIN_TEMPLATE_ARRAY, auditingFields); + + break; + case USER_ACCESS: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.USER_ACCESS_TEMPLATE_ARRAY, auditingFields); + break; + case DISTRIBUTION_REGISTER: + case DISTRIBUTION_UN_REGISTER: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.DISTRIBUTION_REGISTRATION_TEMPLATE_ARRAY, auditingFields); + break; + case UPDATE_RESOURCE_METADATA: + case CREATE_RESOURCE: + case IMPORT_RESOURCE: + ArrayList<AuditingFieldsKeysEnum> createResourceList = new ArrayList(Arrays.asList(AuditingLogFormatConstants.CREATE_RESOURCE_TEMPLATE_PREFIX_ARRAY)); + createResourceList.addAll(Arrays.asList(AuditingLogFormatConstants.CREATE_RESOURCE_TEMPLATE_SUFFIX_ARRAY)); + if (auditEventType == AuditingActionEnum.IMPORT_RESOURCE) { + createResourceList.add(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TOSCA_NODE_TYPE); + } + AuditingFieldsKeysEnum[] createResourceArray = new AuditingFieldsKeysEnum[100]; + createResourceArray = createResourceList.toArray(createResourceArray); + formattedString = buildStringAccrodingToArray(createResourceArray, auditingFields); + break; + case CHECKIN_RESOURCE: + case CHECKOUT_RESOURCE: + case UNDO_CHECKOUT_RESOURCE: + case CERTIFICATION_REQUEST_RESOURCE: + case START_CERTIFICATION_RESOURCE: + case CERTIFICATION_SUCCESS_RESOURCE: + case FAIL_CERTIFICATION_RESOURCE: + case CANCEL_CERTIFICATION_RESOURCE: + ArrayList<AuditingFieldsKeysEnum> checkinFieldsList = new ArrayList(Arrays.asList(AuditingLogFormatConstants.CREATE_RESOURCE_TEMPLATE_PREFIX_ARRAY)); + checkinFieldsList.add(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT); + checkinFieldsList.addAll(Arrays.asList(AuditingLogFormatConstants.CREATE_RESOURCE_TEMPLATE_SUFFIX_ARRAY)); + AuditingFieldsKeysEnum[] checkinFieldsArray = new AuditingFieldsKeysEnum[100]; + checkinFieldsArray = checkinFieldsList.toArray(checkinFieldsArray); + String comment = (String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT); + if (comment == null || comment.equals(Constants.NULL_STRING)) { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, Constants.EMPTY_STRING); + } + formattedString = buildStringAccrodingToArray(checkinFieldsArray, auditingFields); + break; + case ARTIFACT_UPLOAD: + case ARTIFACT_DELETE: + case ARTIFACT_METADATA_UPDATE: + case ARTIFACT_PAYLOAD_UPDATE: + case ARTIFACT_DOWNLOAD: + ArrayList<AuditingFieldsKeysEnum> artifactFieldsList = new ArrayList(Arrays.asList(AuditingLogFormatConstants.CREATE_RESOURCE_TEMPLATE_PREFIX_ARRAY)); + artifactFieldsList.add(AuditingFieldsKeysEnum.AUDIT_PREV_ARTIFACT_UUID); + artifactFieldsList.add(AuditingFieldsKeysEnum.AUDIT_CURR_ARTIFACT_UUID); + artifactFieldsList.add(AuditingFieldsKeysEnum.AUDIT_ARTIFACT_DATA); + artifactFieldsList.addAll(Arrays.asList(AuditingLogFormatConstants.CREATE_RESOURCE_TEMPLATE_SUFFIX_ARRAY)); + artifactFieldsList.addAll(Arrays.asList(AuditingLogFormatConstants.EXTERNAL_DOWNLOAD_ARTIFACT_ARRAY)); + AuditingFieldsKeysEnum[] artifactFieldsArray = new AuditingFieldsKeysEnum[100]; + artifactFieldsArray = artifactFieldsList.toArray(artifactFieldsArray); + formattedString = buildStringAccrodingToArray(artifactFieldsArray, auditingFields); + break; + case DOWNLOAD_ARTIFACT: + ArrayList<AuditingFieldsKeysEnum> downloadArtifactFieldsList = new ArrayList(Arrays.asList(AuditingLogFormatConstants.EXTERNAL_DOWNLOAD_ARTIFACT_ARRAY)); + AuditingFieldsKeysEnum[] downloadArtifactFieldsArray = new AuditingFieldsKeysEnum[100]; + artifactFieldsArray = downloadArtifactFieldsList.toArray(downloadArtifactFieldsArray); + formattedString = buildStringAccrodingToArray(artifactFieldsArray, auditingFields); + break; + case DISTRIBUTION_STATE_CHANGE_REQUEST: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.ACTIVATE_DISTRIBUTION_ARRAY, auditingFields); + break; + case DISTRIBUTION_STATE_CHANGE_APPROV: + case DISTRIBUTION_STATE_CHANGE_REJECT: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.CHANGE_DISTRIBUTION_STATUS_ARRAY, auditingFields); + break; + case CREATE_DISTRIBUTION_TOPIC: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.CREATE_TOPIC_TEMPLATE_ARRAY, auditingFields); + break; + case ADD_KEY_TO_TOPIC_ACL: + case REMOVE_KEY_FROM_TOPIC_ACL: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.ADD_REMOVE_TOPIC_KEY_ACL_TEMPLATE_ARRAY, auditingFields); + break; + case DISTRIBUTION_STATUS: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.DISTRIBUTION_STATUS_TEMPLATE_ARRAY, auditingFields); + break; + case DISTRIBUTION_NOTIFY: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.DISTRIBUTION_NOTIFY_ARRAY, auditingFields); + break; + case DISTRIBUTION_DEPLOY: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.DISTRIBUTION_DEPLOY_ARRAY, auditingFields); + break; + case GET_UEB_CLUSTER: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.GET_UEB_CLUSTER_ARRAY, auditingFields); + break; + case DISTRIBUTION_ARTIFACT_DOWNLOAD: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.DISTRIBUTION_DOWNLOAD_TEMPLATE_ARRAY, auditingFields); + break; + case AUTH_REQUEST: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.AUTH_TEMPLATE_ARRAY, auditingFields); + break; + case ADD_ECOMP_USER_CREDENTIALS: + case GET_ECOMP_USER_CREDENTIALS: + case DELETE_ECOMP_USER_CREDENTIALS: + case UPDATE_ECOMP_USER_CREDENTIALS: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.ECOMP_USER_TEMPLATE_ARRAY, auditingFields); + break; + case ADD_CATEGORY: + case ADD_SUB_CATEGORY: + case ADD_GROUPING: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.CATEGORY_TEMPLATE_ARRAY, auditingFields); + break; + case GET_USERS_LIST: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.GET_USERS_LIST_TEMPLATE_ARRAY, auditingFields); + break; + case GET_CATEGORY_HIERARCHY: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.GET_CATEGORY_HIERARCHY_TEMPLATE_ARRAY, auditingFields); + break; + case GET_ASSET_LIST: + case GET_FILTERED_ASSET_LIST: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.EXTERNAL_GET_ASSET_LIST_TEMPLATE_ARRAY, auditingFields); + break; + case GET_ASSET_METADATA: + case GET_TOSCA_MODEL: + formattedString = buildStringAccrodingToArray(AuditingLogFormatConstants.EXTERNAL_GET_ASSET_TEMPLATE_ARRAY, auditingFields); + break; + case ARTIFACT_UPLOAD_BY_API: + case ARTIFACT_DELETE_BY_API: + case ARTIFACT_UPDATE_BY_API: + ArrayList<AuditingFieldsKeysEnum> uploadArtifactFieldsList = new ArrayList(Arrays.asList(AuditingLogFormatConstants.EXTERNAL_CRUD_API_ARTIFACT_ARRAY)); + AuditingFieldsKeysEnum[] uploadArtifactFieldsArray = new AuditingFieldsKeysEnum[100]; + artifactFieldsArray = uploadArtifactFieldsList.toArray(uploadArtifactFieldsArray); + formattedString = buildStringAccrodingToArray(artifactFieldsArray, auditingFields); + break; + default: + break; + } + + return formattedString; + } + + private static StringBuilder buildStringAccrodingToArray(AuditingFieldsKeysEnum[] sortedFieldsArray, EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + StringBuilder formattedString = new StringBuilder(); + for (int i = 0; i < sortedFieldsArray.length; i++) { + AuditingFieldsKeysEnum key = sortedFieldsArray[i]; + + Object fieldVal = auditingFields.get(key); + if (fieldVal != null) { + formattedString.append(key.getDisplayName()).append(" = \"").append(fieldVal).append("\""); + if (i < sortedFieldsArray.length - 1) { + formattedString.append(" "); + } + } + } + return formattedString; + } + + protected static String getModifier(String modifierName, String modifierUid) { + if (modifierUid == null || modifierUid.equals(Constants.EMPTY_STRING)) { + return Constants.EMPTY_STRING; + } + StringBuilder sb = new StringBuilder(); + if (modifierName != null) { + sb.append(modifierName); + } + sb.append("(").append(modifierUid).append(")"); + return sb.toString(); + } + + protected static String getUser(String userData) { + StringBuilder sb = new StringBuilder(); + sb.append(userData); + return sb.toString(); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingManager.java new file mode 100644 index 0000000000..aa5afa4a8e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/auditing/impl/AuditingManager.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.auditing.impl; + +import java.util.EnumMap; +import java.util.Map.Entry; + +import javax.annotation.Resource; + +import org.openecomp.sdc.be.auditing.api.IAuditingManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.cassandra.AuditCassandraDao; +import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; +import org.openecomp.sdc.be.dao.impl.AuditingDao; +import org.openecomp.sdc.be.resources.data.auditing.AuditRecordFactory; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.resources.data.auditing.AuditingGenericEvent; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.ThreadLocalsHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("auditingManager") +public class AuditingManager implements IAuditingManager { + + private static Logger log = LoggerFactory.getLogger(AuditingManager.class.getName()); + + @Resource + private AuditingDao auditingDao; + @Autowired + private AuditCassandraDao cassandraDao; + + @Override + public void auditEvent(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + try { + boolean disableAudit = ConfigurationManager.getConfigurationManager().getConfiguration().isDisableAudit(); + if (disableAudit) { + return; + } + // Adding UUID from thread local + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_REQUEST_ID, ThreadLocalsHolder.getUuid()); + + Object status = auditingFields.get(AuditingFieldsKeysEnum.AUDIT_STATUS); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, String.valueOf(status)); + + // normalizing empty string values - US471661 + normalizeEmptyAuditStringValues(auditingFields); + + // Format modifier + formatModifier(auditingFields); + + // Format user + formatUser(auditingFields); + + // Logging the event + AuditingLogFormatUtil.logAuditEvent(auditingFields); + + // Determining the type of the auditing data object + AuditingActionEnum actionEnum = AuditingActionEnum.getActionByName((String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_ACTION)); + log.info("audit event {} of type {}", actionEnum.getName(), actionEnum.getAuditingEsType()); + ActionStatus addRecordStatus = auditingDao.addRecord(auditingFields, actionEnum.getAuditingEsType()); + if (!addRecordStatus.equals(ActionStatus.OK)) { + log.warn("Failed to persist auditing event: {}", addRecordStatus.name()); + } + + AuditingGenericEvent recordForCassandra = AuditRecordFactory.createAuditRecord(auditingFields); + if (recordForCassandra != null) { + CassandraOperationStatus result = cassandraDao.saveRecord(recordForCassandra); + if (!result.equals(CassandraOperationStatus.OK)) { + log.warn("Failed to persist to cassandra auditing event: {}", addRecordStatus.name()); + } + } + + } catch (Exception e) { + // Error during auditing shouldn't terminate flow + log.warn("Error during auditEvent: {}", e); + } + } + + private void formatUser(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + if (auditingFields.get(AuditingFieldsKeysEnum.AUDIT_USER_UID) != null) { + String userDetails = (String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_USER_UID); + + String user = AuditingLogFormatUtil.getUser(userDetails); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_UID, user); + } + } + + private void formatModifier(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + String modifier = AuditingLogFormatUtil.getModifier((String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME), (String) auditingFields.get(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID)); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier); + auditingFields.remove(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME); + } + + private void normalizeEmptyAuditStringValues(EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + for (Entry<AuditingFieldsKeysEnum, Object> auditingEntry : auditingFields.entrySet()) { + if (auditingEntry.getKey().getValueClass().equals(String.class)) { + String auditingValue = (String) auditingEntry.getValue(); + boolean isEmpty = false; + if (auditingValue != null) { + String trimmedValue = auditingValue.trim(); + if ((trimmedValue.equals(Constants.EMPTY_STRING)) || trimmedValue.equals(Constants.NULL_STRING) || trimmedValue.equals(Constants.DOUBLE_NULL_STRING)) { + isEmpty = true; + } + } else {// is null + isEmpty = true; + } + // Normalizing to "" + if (isEmpty) { + auditingEntry.setValue(Constants.EMPTY_STRING); + } + } + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/clean/AsdcComponentsCleanerTask.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/clean/AsdcComponentsCleanerTask.java new file mode 100644 index 0000000000..b3b842b9e4 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/clean/AsdcComponentsCleanerTask.java @@ -0,0 +1,175 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.clean; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.CleanComponentsConfiguration; +import org.openecomp.sdc.be.config.Configuration; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component("asdcComponentsCleaner") +public class AsdcComponentsCleanerTask implements Runnable { + + private static Logger log = LoggerFactory.getLogger(AsdcComponentsCleanerTask.class.getName()); + + @javax.annotation.Resource + private ComponentsCleanBusinessLogic componentsCleanBusinessLogic = null; + + private List<NodeTypeEnum> componentsToClean; + private long cleaningIntervalInMinutes; + + private ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("ComponentsCleanThread-%d").build()); + ScheduledFuture<?> scheduledFuture = null; + + @PostConstruct + public void init() { + log.trace("Enter init method of AsdcComponentsCleaner"); + Configuration configuration = ConfigurationManager.getConfigurationManager().getConfiguration(); + CleanComponentsConfiguration cleanComponentsConfiguration = configuration.getCleanComponentsConfiguration(); + + if (cleanComponentsConfiguration == null) { + log.info("ERROR - configuration is not valid!!! missing cleanComponentsConfiguration"); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeComponentCleanerSystemError, "AsdcComponentsCleanerTask.init()", "AsdcComponentsCleanerTask.init()"); + BeEcompErrorManager.getInstance().logBeComponentCleanerSystemError("AsdcComponentsCleanerTask-init", "fecth configuration"); + return; + + } + componentsToClean = new ArrayList<NodeTypeEnum>(); + List<String> components = cleanComponentsConfiguration.getComponentsToClean(); + if (components == null) { + log.info("no component were configured for cleaning"); + } + for (String component : components) { + NodeTypeEnum typeEnum = NodeTypeEnum.getByNameIgnoreCase(component); + if (typeEnum != null) + componentsToClean.add(typeEnum); + } + + long intervalInMinutes = cleanComponentsConfiguration.getCleanIntervalInMinutes(); + + if (intervalInMinutes < 1) { + log.warn("cleaningIntervalInMinutes value should be greater than or equal to 1 minute. use default"); + intervalInMinutes = 60; + } + cleaningIntervalInMinutes = intervalInMinutes; + + startTask(); + + log.trace("End init method of AsdcComponentsCleaner"); + } + + @PreDestroy + public void destroy() { + this.stopTask(); + shutdownExecutor(); + } + + public void startTask() { + + log.debug("start task for cleaning components"); + + try { + + if (scheduledService != null) { + log.debug("Start Cleaning components task. interval {} minutes", cleaningIntervalInMinutes); + scheduledFuture = scheduledService.scheduleAtFixedRate(this, 5, cleaningIntervalInMinutes, TimeUnit.MINUTES); + + } + } catch (Exception e) { + log.debug("unexpected error occured", e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeComponentCleanerSystemError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeComponentCleanerSystemError("AsdcComponentsCleanerTask-startTask", e.getMessage()); + + } + } + + public void stopTask() { + if (scheduledFuture != null) { + boolean result = scheduledFuture.cancel(true); + log.debug("Stop cleaning task. result = {}", result); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + if (false == result) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeComponentCleanerSystemError, methodName, "try to stop the polling task"); + BeEcompErrorManager.getInstance().logBeComponentCleanerSystemError("AsdcComponentsCleanerTask-stopTask", "try to stop the polling task"); + } + scheduledFuture = null; + } + + } + + private void shutdownExecutor() { + if (scheduledService == null) + return; + + scheduledService.shutdown(); // Disable new tasks from being submitted + try { + // Wait a while for existing tasks to terminate + if (!scheduledService.awaitTermination(60, TimeUnit.SECONDS)) { + scheduledService.shutdownNow(); // Cancel currently executing + // tasks + // Wait a while for tasks to respond to being cancelled + if (!scheduledService.awaitTermination(60, TimeUnit.SECONDS)) + log.debug("Pool did not terminate"); + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + scheduledService.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } + + @Override + public void run() { + try { + componentsCleanBusinessLogic.cleanComponents(componentsToClean); + } catch (Throwable e) { + log.error("unexpected error occured", e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeComponentCleanerSystemError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeComponentCleanerSystemError("AsdcComponentsCleanerTask-run", e.getMessage()); + } + + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/clean/ComponentsCleanBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/clean/ComponentsCleanBusinessLogic.java new file mode 100644 index 0000000000..b12b55ba8b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/clean/ComponentsCleanBusinessLogic.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.clean; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.components.impl.BaseBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("componentsCleanBusinessLogic") +public class ComponentsCleanBusinessLogic extends BaseBusinessLogic { + + @Autowired + private ResourceBusinessLogic resourceBusinessLogic; + + @Autowired + private ServiceBusinessLogic serviceBusinessLogic; + + private static Logger log = LoggerFactory.getLogger(ComponentsCleanBusinessLogic.class.getName()); + + public Map<NodeTypeEnum, Either<List<String>, ResponseFormat>> cleanComponents(List<NodeTypeEnum> componentsToClean) { + + Map<NodeTypeEnum, Either<List<String>, ResponseFormat>> cleanedComponents = new HashMap<NodeTypeEnum, Either<List<String>, ResponseFormat>>(); + + log.trace("start cleanComponents"); + for (NodeTypeEnum type : componentsToClean) { + switch (type) { + case Resource: + processDeletionForType(cleanedComponents, NodeTypeEnum.Resource, resourceBusinessLogic); + break; + case Service: + processDeletionForType(cleanedComponents, NodeTypeEnum.Service, serviceBusinessLogic); + break; + default: + log.debug("{} component type does not have cleaning method defined", type); + break; + } + } + + log.trace("end cleanComponents"); + return cleanedComponents; + } + + private void processDeletionForType(Map<NodeTypeEnum, Either<List<String>, ResponseFormat>> cleanedComponents, NodeTypeEnum type, ComponentBusinessLogic componentBusinessLogic) { + Either<List<String>, ResponseFormat> deleteMarkedResources = componentBusinessLogic.deleteMarkedComponents(); + if (deleteMarkedResources.isRight()) { + log.debug("failed to clean deleted components of type {}. error: {}", type, deleteMarkedResources.right().value().getFormattedMessage()); + } else { + if (log.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("list of deleted components - type " + type + ": "); + for (String id : deleteMarkedResources.left().value()) { + sb.append(id).append(", "); + } + log.debug(sb.toString()); + } + } + cleanedComponents.put(type, deleteMarkedResources); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ArtifactInfoImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ArtifactInfoImpl.java new file mode 100644 index 0000000000..e1a1270fe3 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ArtifactInfoImpl.java @@ -0,0 +1,196 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; + +public class ArtifactInfoImpl implements IArtifactInfo { + + private String artifactName; + private ArtifactTypeEnum artifactType; + private String artifactURL; + private String artifactChecksum; + private String artifactDescription; + private Integer artifactTimeout; + private String artifactUUID; + private String artifactVersion; + private String generatedFromUUID; + private List<String> relatedArtifacts; + + public ArtifactInfoImpl() { + } + + private ArtifactInfoImpl(ArtifactDefinition artifactDef, String generatedFromUUID, List<String> relatedArtifacts) { + artifactName = artifactDef.getArtifactName(); + artifactType = ArtifactTypeEnum.findType(artifactDef.getArtifactType()); + artifactChecksum = artifactDef.getArtifactChecksum(); + artifactDescription = artifactDef.getDescription(); + artifactTimeout = artifactDef.getTimeout(); + artifactUUID = artifactDef.getArtifactUUID(); + artifactVersion = artifactDef.getArtifactVersion(); + this.relatedArtifacts = relatedArtifacts; + this.generatedFromUUID = generatedFromUUID; + } + + public static List<ArtifactInfoImpl> convertToArtifactInfoImpl(Service service, ComponentInstance resourceInstance, Collection<ArtifactDefinition> list) { + List<ArtifactInfoImpl> ret = new ArrayList<ArtifactInfoImpl>(); + Map<String, List<ArtifactDefinition>> artifactIdToDef = list.stream().collect(Collectors.groupingBy(ArtifactDefinition::getUniqueId)); + if (list != null) { + for (ArtifactDefinition artifactDef : list) { + String generatedFromUUID = null; + if (artifactDef.getGeneratedFromId() != null && !artifactDef.getGeneratedFromId().isEmpty()) { + ArtifactDefinition artifactFrom = artifactIdToDef.get(artifactDef.getGeneratedFromId()).get(0); + generatedFromUUID = artifactFrom.getArtifactUUID(); + } + ArtifactInfoImpl artifactInfoImpl = new ArtifactInfoImpl(artifactDef, generatedFromUUID, getUpdatedRequiredArtifactsFromNamesToUuids(artifactDef, resourceInstance.getDeploymentArtifacts())); + String artifactURL = ServiceDistributionArtifactsBuilder.buildResourceInstanceArtifactUrl(service, resourceInstance, artifactDef.getArtifactName()); + artifactInfoImpl.setArtifactURL(artifactURL); + ret.add(artifactInfoImpl); + } + } + return ret; + + } + + public static List<ArtifactInfoImpl> convertServiceArtifactToArtifactInfoImpl(Service service, Collection<ArtifactDefinition> list) { + List<ArtifactInfoImpl> ret = new ArrayList<ArtifactInfoImpl>(); + Map<String, List<ArtifactDefinition>> artifactIdToDef = list.stream().collect(Collectors.groupingBy(ArtifactDefinition::getUniqueId)); + if (list != null) { + for (ArtifactDefinition artifactDef : list) { + String generatedFromUUID = null; + if (artifactDef.getGeneratedFromId() != null && !artifactDef.getGeneratedFromId().isEmpty()) { + ArtifactDefinition artifactFrom = artifactIdToDef.get(artifactDef.getGeneratedFromId()).get(0); + generatedFromUUID = artifactFrom.getArtifactUUID(); + } + ArtifactInfoImpl artifactInfoImpl = new ArtifactInfoImpl(artifactDef, generatedFromUUID, getUpdatedRequiredArtifactsFromNamesToUuids(artifactDef, service.getDeploymentArtifacts())); + String artifactURL = ServiceDistributionArtifactsBuilder.buildServiceArtifactUrl(service, artifactDef.getArtifactName()); + artifactInfoImpl.setArtifactURL(artifactURL); + ret.add(artifactInfoImpl); + } + } + return ret; + + } + + private static List<String> getUpdatedRequiredArtifactsFromNamesToUuids(ArtifactDefinition artifactDefinition, Map<String, ArtifactDefinition> artifacts) { + List<String> requiredArtifacts = null; + if (artifactDefinition != null && artifactDefinition.getRequiredArtifacts() != null && !artifactDefinition.getRequiredArtifacts().isEmpty() && artifacts != null && !artifacts.isEmpty()) { + requiredArtifacts = artifacts.values().stream().filter(art -> artifactDefinition.getRequiredArtifacts().contains(art.getArtifactName())).map(art -> art.getArtifactUUID()).collect(Collectors.toList()); + } + return requiredArtifacts; + } + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + + public ArtifactTypeEnum getArtifactType() { + return artifactType; + } + + public void setArtifactType(ArtifactTypeEnum artifactType) { + this.artifactType = artifactType; + } + + public String getArtifactURL() { + return artifactURL; + } + + public void setArtifactURL(String artifactURL) { + this.artifactURL = artifactURL; + } + + public String getArtifactChecksum() { + return artifactChecksum; + } + + public void setArtifactChecksum(String artifactChecksum) { + this.artifactChecksum = artifactChecksum; + } + + public String getArtifactDescription() { + return artifactDescription; + } + + public void setArtifactDescription(String artifactDescription) { + this.artifactDescription = artifactDescription; + } + + public Integer getArtifactTimeout() { + return artifactTimeout; + } + + public void setArtifactTimeout(Integer artifactTimeout) { + this.artifactTimeout = artifactTimeout; + } + + public List<String> getRelatedArtifacts() { + return relatedArtifacts; + } + + public void setRelatedArtifacts(List<String> relatedArtifacts) { + this.relatedArtifacts = relatedArtifacts; + } + + @Override + public String toString() { + return "ArtifactInfoImpl [artifactName=" + artifactName + ", artifactType=" + artifactType + ", artifactURL=" + artifactURL + ", artifactChecksum=" + artifactChecksum + ", artifactDescription=" + artifactDescription + ", artifactTimeout=" + + artifactTimeout + ", artifactUUID=" + artifactUUID + ", artifactVersion=" + artifactVersion + ", generatedFromUUID=" + generatedFromUUID + ", relatedArtifacts=" + relatedArtifacts + "]"; + } + + public String getArtifactUUID() { + return artifactUUID; + } + + public void setArtifactUUID(String artifactUUID) { + this.artifactUUID = artifactUUID; + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public String getGeneratedFromUUID() { + return generatedFromUUID; + } + + public void setGeneratedFromUUID(String generatedFromUUID) { + this.generatedFromUUID = generatedFromUUID; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/CambriaErrorResponse.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/CambriaErrorResponse.java new file mode 100644 index 0000000000..149ea2286a --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/CambriaErrorResponse.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.distribution.api.client.CambriaOperationStatus; + +public class CambriaErrorResponse { + + public static final int HTTP_OK = 200; + + public static final int HTTP_INTERNAL_SERVER_ERROR = 500; + + CambriaOperationStatus operationStatus; + Integer httpCode; + List<String> variables = new ArrayList<String>(); + + public CambriaErrorResponse() { + super(); + } + + public CambriaErrorResponse(CambriaOperationStatus operationStatus) { + super(); + this.operationStatus = operationStatus; + } + + public CambriaErrorResponse(CambriaOperationStatus operationStatus, Integer httpCode) { + super(); + this.operationStatus = operationStatus; + this.httpCode = httpCode; + } + + public CambriaOperationStatus getOperationStatus() { + return operationStatus; + } + + public void setOperationStatus(CambriaOperationStatus operationStatus) { + this.operationStatus = operationStatus; + } + + public Integer getHttpCode() { + return httpCode; + } + + public void setHttpCode(Integer httpCode) { + this.httpCode = httpCode; + } + + public void addVariable(String variable) { + variables.add(variable); + } + + public List<String> getVariables() { + return variables; + } + + public void setVariables(List<String> variables) { + this.variables = variables; + } + + @Override + public String toString() { + return "CambriaErrorResponse [operationStatus=" + operationStatus + ", httpCode=" + httpCode + ", variables=" + variables + "]"; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/CambriaHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/CambriaHandler.java new file mode 100644 index 0000000000..3528ed9be3 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/CambriaHandler.java @@ -0,0 +1,610 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.distribution.api.client.CambriaOperationStatus; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.att.nsa.apiClient.http.HttpException; +import com.att.nsa.apiClient.http.HttpObjectNotFoundException; +import com.att.nsa.cambria.client.CambriaBatchingPublisher; +import com.att.nsa.cambria.client.CambriaClient.CambriaApiException; +import com.att.nsa.cambria.client.CambriaClientBuilders.TopicManagerBuilder; +import com.att.nsa.cambria.client.CambriaClientBuilders.PublisherBuilder; +import com.att.nsa.cambria.client.CambriaClientBuilders.ConsumerBuilder; +import com.att.nsa.cambria.client.CambriaClientBuilders.IdentityManagerBuilder; +import com.att.nsa.cambria.client.CambriaConsumer; +import com.att.nsa.cambria.client.CambriaIdentityManager; +import com.att.nsa.cambria.client.CambriaPublisher.message; +import com.att.nsa.cambria.client.CambriaTopicManager; +import com.google.gson.Gson; + +import fj.data.Either; + +public class CambriaHandler { + + private static Logger logger = LoggerFactory.getLogger(CambriaHandler.class.getName()); + + public static String PARTITION_KEY = "asdc" + "aa"; + + private Gson gson = new Gson(); + + /** + * process the response error from Cambria client + * + * @param message + * @return + */ + private Integer processMessageException(String message) { + + String[] patterns = { "(HTTP Status )(\\d\\d\\d)", "(HTTP/\\d.\\d )(\\d\\d\\d)" }; + + Integer result = checkPattern(patterns[0], message, 2); + if (result != null) { + return result; + } + result = checkPattern(patterns[1], message, 2); + + return result; + + } + + /** + * check whether the message has a match with a given pattern inside it + * + * @param patternStr + * @param message + * @param groupIndex + * @return + */ + private Integer checkPattern(String patternStr, String message, int groupIndex) { + Integer result = null; + + Pattern pattern = Pattern.compile(patternStr); + Matcher matcher = pattern.matcher(message); + boolean find = matcher.find(); + if (find) { + String httpCode = matcher.group(groupIndex); + if (httpCode != null) { + try { + result = Integer.valueOf(httpCode); + } catch (NumberFormatException e) { + logger.debug("Failed to parse http code {}", httpCode); + } + } + } + return result; + } + + /** + * retrieve all topics from U-EB server + * + * @param hostSet + * @return + */ + public Either<Set<String>, CambriaErrorResponse> getTopics(List<String> hostSet) { + + CambriaTopicManager createTopicManager = null; + try { + + createTopicManager = new TopicManagerBuilder().usingHosts(hostSet).build(); + Set<String> topics = createTopicManager.getTopics(); + + if (topics == null || true == topics.isEmpty()) { + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.NOT_FOUND, null); + return Either.right(cambriaErrorResponse); + } + + return Either.left(topics); + + } catch (IOException | GeneralSecurityException e) { + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + CambriaErrorResponse cambriaErrorResponse = processError(e); + + logger.debug("Failed to fetch topics from U-EB server", e); + writeErrorToLog(cambriaErrorResponse, e.getMessage(), methodName, "get topics"); + + return Either.right(cambriaErrorResponse); + } finally { + if (createTopicManager != null) { + createTopicManager.close(); + } + } + + } + + /** + * process the error message from Cambria client. + * + * set Cambria status and http code in case we succeed to fetch it + * + * @param errorMessage + * @return + */ + private CambriaErrorResponse processError(Exception e) { + + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(); + + Integer httpCode = processMessageException(e.getMessage()); + + if (httpCode != null) { + cambriaErrorResponse.setHttpCode(httpCode); + switch (httpCode.intValue()) { + + case 401: + cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.AUTHENTICATION_ERROR); + break; + case 409: + cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.TOPIC_ALREADY_EXIST); + break; + case 500: + cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.INTERNAL_SERVER_ERROR); + break; + default: + cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.CONNNECTION_ERROR); + } + } else { + + boolean found = false; + Throwable throwable = e.getCause(); + if (throwable != null) { + String message = throwable.getMessage(); + + Throwable cause = throwable.getCause(); + + if (cause != null) { + Class<?> clazz = cause.getClass(); + String className = clazz.getName(); + if (className.endsWith("UnknownHostException")) { + cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.UNKNOWN_HOST_ERROR); + cambriaErrorResponse.addVariable(message); + found = true; + } + } + } + + if (false == found) { + cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.CONNNECTION_ERROR); + cambriaErrorResponse.setHttpCode(HttpStatus.SC_INTERNAL_SERVER_ERROR); + } + } + + return cambriaErrorResponse; + } + + /** + * write the error to the log + * + * @param cambriaErrorResponse + * @param errorMessage + * @param methodName + * @param operationDesc + */ + private void writeErrorToLog(CambriaErrorResponse cambriaErrorResponse, String errorMessage, String methodName, String operationDesc) { + + String httpCode = (cambriaErrorResponse.getHttpCode() == null ? "" : String.valueOf(cambriaErrorResponse.getHttpCode())); + + switch (cambriaErrorResponse.getOperationStatus()) { + case UNKNOWN_HOST_ERROR: + String hostname = cambriaErrorResponse.getVariables().get(0); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebUnkownHostError, methodName, hostname); + BeEcompErrorManager.getInstance().logBeUebUnkownHostError(methodName, httpCode); + break; + case AUTHENTICATION_ERROR: + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebAuthenticationError, methodName, httpCode); + BeEcompErrorManager.getInstance().logBeUebAuthenticationError(methodName, httpCode); + break; + case CONNNECTION_ERROR: + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebConnectionError, methodName, httpCode); + BeEcompErrorManager.getInstance().logBeUebConnectionError(methodName, httpCode); + break; + + case INTERNAL_SERVER_ERROR: + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, methodName, operationDesc); + BeEcompErrorManager.getInstance().logBeUebSystemError(methodName, operationDesc); + break; + + } + + } + + /** + * create a topic if it does not exists in the topicsList + * + * @param hostSet + * - list of U-EB servers + * @param apiKey + * @param secretKey + * @param topicsList + * - list of exists topics + * @param topicName + * - topic to create + * @param partitionCount + * @param replicationCount + * @return + */ + public CambriaErrorResponse createTopic(Collection<String> hostSet, String apiKey, String secretKey, String topicName, int partitionCount, int replicationCount) { + + CambriaTopicManager createTopicManager = null; + try { + createTopicManager = new TopicManagerBuilder().usingHosts(hostSet).authenticatedBy(apiKey, secretKey).build(); + createTopicManager.createTopic(topicName, "ASDC distribution notification topic", partitionCount, replicationCount); + + } catch (GeneralSecurityException | HttpException | IOException e) { + logger.debug("Failed to create topic {}", topicName, e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + CambriaErrorResponse cambriaErrorResponse = processError(e); + + if (cambriaErrorResponse.getOperationStatus() != CambriaOperationStatus.TOPIC_ALREADY_EXIST) { + writeErrorToLog(cambriaErrorResponse, e.getMessage(), methodName, "create topic"); + } + + return cambriaErrorResponse; + + } finally { + if (createTopicManager != null) { + createTopicManager.close(); + } + } + return new CambriaErrorResponse(CambriaOperationStatus.OK); + } + + public CambriaErrorResponse unRegisterFromTopic(Collection<String> hostSet, String topicName, String managerApiKey, String managerSecretKey, String subscriberApiKey, SubscriberTypeEnum subscriberTypeEnum) { + CambriaTopicManager createTopicManager = null; + try { + createTopicManager = new TopicManagerBuilder().usingHosts(hostSet).authenticatedBy(managerApiKey, managerSecretKey).build(); + + if (subscriberTypeEnum == SubscriberTypeEnum.PRODUCER) { + createTopicManager.revokeProducer(topicName, subscriberApiKey); + } else { + createTopicManager.revokeConsumer(topicName, subscriberApiKey); + } + + } catch (HttpObjectNotFoundException | GeneralSecurityException e) { + logger.debug("Failed to unregister {} from topic {} as {}", managerApiKey, topicName, subscriberTypeEnum.toString().toLowerCase(), e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebObjectNotFoundError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeUebObjectNotFoundError(methodName, e.getMessage()); + + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.OBJECT_NOT_FOUND, HttpStatus.SC_NOT_FOUND); + return cambriaErrorResponse; + + } catch (HttpException | IOException e) { + logger.debug("Failed to unregister {} from topic {} as producer", managerApiKey, topicName, e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + CambriaErrorResponse cambriaErrorResponse = processError(e); + + writeErrorToLog(cambriaErrorResponse, e.getMessage(), methodName, "unregister from topic as " + subscriberTypeEnum.toString().toLowerCase()); + + return cambriaErrorResponse; + } finally { + if (createTopicManager != null) { + createTopicManager.close(); + } + } + + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.OK, HttpStatus.SC_OK); + return cambriaErrorResponse; + } + + /** + * + * register a public key (subscriberId) to a given topic as a CONSUMER or PRODUCER + * + * @param hostSet + * @param topicName + * @param managerApiKey + * @param managerSecretKey + * @param subscriberApiKey + * @param subscriberTypeEnum + * @return + */ + public CambriaErrorResponse registerToTopic(Collection<String> hostSet, String topicName, String managerApiKey, String managerSecretKey, String subscriberApiKey, SubscriberTypeEnum subscriberTypeEnum) { + + CambriaTopicManager createTopicManager = null; + try { + createTopicManager = new TopicManagerBuilder().usingHosts(hostSet).authenticatedBy(managerApiKey, managerSecretKey).build(); + + if (subscriberTypeEnum == SubscriberTypeEnum.PRODUCER) { + createTopicManager.allowProducer(topicName, subscriberApiKey); + } else { + createTopicManager.allowConsumer(topicName, subscriberApiKey); + } + + } catch (HttpObjectNotFoundException | GeneralSecurityException e) { + logger.debug("Failed to register {} to topic {} as {}", managerApiKey, topicName, subscriberTypeEnum.toString().toLowerCase(), e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebObjectNotFoundError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeUebObjectNotFoundError(methodName, e.getMessage()); + + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.OBJECT_NOT_FOUND, HttpStatus.SC_NOT_FOUND); + return cambriaErrorResponse; + + } catch (HttpException | IOException e) { + logger.debug("Failed to register {} to topic {} as {}", managerApiKey, topicName, subscriberTypeEnum.toString().toLowerCase(), e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + CambriaErrorResponse cambriaErrorResponse = processError(e); + + writeErrorToLog(cambriaErrorResponse, e.getMessage(), methodName, "register to topic as " + subscriberTypeEnum.toString().toLowerCase()); + + return cambriaErrorResponse; + } finally { + if (createTopicManager != null) { + createTopicManager.close(); + } + } + + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.OK, HttpStatus.SC_OK); + return cambriaErrorResponse; + } + + /** + * create and retrieve a Cambria Consumer for a specific topic + * + * @param hostSet + * @param topicName + * @param apiKey + * @param secretKey + * @param consumerId + * @param consumerGroup + * @param timeoutMS + * @return + * @throws Exception + */ + public CambriaConsumer createConsumer(Collection<String> hostSet, String topicName, String apiKey, String secretKey, String consumerId, String consumerGroup, int timeoutMS) throws Exception { + + CambriaConsumer consumer = new ConsumerBuilder().authenticatedBy(apiKey, secretKey).knownAs(consumerGroup, consumerId).onTopic(topicName).usingHosts(hostSet).withSocketTimeout(timeoutMS).build(); + consumer.setApiCredentials(apiKey, secretKey); + return consumer; + } + + public void closeConsumer(CambriaConsumer consumer) { + + if (consumer != null) { + consumer.close(); + } + + } + + /** + * use the topicConsumer to fetch messages from topic. in case no messages were fetched, empty ArrayList will be returned (not error) + * + * @param topicConsumer + * @return + */ + public Either<Iterable<String>, CambriaErrorResponse> fetchFromTopic(CambriaConsumer topicConsumer) { + + try { + Iterable<String> messages = topicConsumer.fetch(); + if (messages == null) { + messages = new ArrayList<String>(); + } + return Either.left(messages); + + } catch (IOException e) { + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + CambriaErrorResponse cambriaErrorResponse = processError(e); + + logger.debug("Failed to fetch from U-EB topic. error={}", e.getMessage()); + writeErrorToLog(cambriaErrorResponse, e.getMessage(), methodName, "get messages from topic"); + + return Either.right(cambriaErrorResponse); + + } catch (Exception e) { + logger.debug("Failed to fetch from U-EB topic", e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(methodName, e.getMessage()); + + CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, HttpStatus.SC_INTERNAL_SERVER_ERROR); + return Either.right(cambriaErrorResponse); + } + } + + /** + * Publish notification message to a given queue + * + * @param topicName + * @param uebPublicKey + * @param uebSecretKey + * @param uebServers + * @param data + * @return + */ + public CambriaErrorResponse sendNotification(String topicName, String uebPublicKey, String uebSecretKey, List<String> uebServers, INotificationData data) { + + CambriaBatchingPublisher createSimplePublisher = null; + + try { + + String json = gson.toJson(data); + logger.trace("Before sending notification data {} to topic {}", json, topicName); + + createSimplePublisher = new PublisherBuilder().onTopic(topicName).usingHosts(uebServers).build(); + createSimplePublisher.setApiCredentials(uebPublicKey, uebSecretKey); + + int result = createSimplePublisher.send(PARTITION_KEY, json); + + try { + Thread.sleep(1 * 1000); + } catch (InterruptedException e) { + logger.debug("Failed during sleep after sending the message.", e); + } + + logger.debug("After sending notification data to topic {}. result is {}", topicName, result); + + CambriaErrorResponse response = new CambriaErrorResponse(CambriaOperationStatus.OK, 200); + + return response; + + } catch (IOException | GeneralSecurityException e) { + logger.debug("Failed to send notification {} to topic {} ", data, topicName, e); + + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + CambriaErrorResponse cambriaErrorResponse = processError(e); + + writeErrorToLog(cambriaErrorResponse, e.getMessage(), methodName, "send notification"); + + return cambriaErrorResponse; + } finally { + if (createSimplePublisher != null) { + logger.debug("Before closing publisher"); + createSimplePublisher.close(); + logger.debug("After closing publisher"); + } + } + } + + private String convertListToString(List<String> list) { + StringBuilder builder = new StringBuilder(); + + if (list != null) { + for (int i = 0; i < list.size(); i++) { + builder.append(list.get(i)); + if (i < list.size() - 1) { + builder.append(","); + } + } + } + + return builder.toString(); + } + + public CambriaErrorResponse sendNotificationAndClose(String topicName, String uebPublicKey, String uebSecretKey, List<String> uebServers, INotificationData data, long waitBeforeCloseTimeout) { + + CambriaBatchingPublisher createSimplePublisher = null; + + CambriaErrorResponse response = null; + try { + + String json = gson.toJson(data); + logger.debug("Before sending notification data {} to topic {}", json, topicName); + + createSimplePublisher = new PublisherBuilder().onTopic(topicName).usingHosts(uebServers).build(); + createSimplePublisher.setApiCredentials(uebPublicKey, uebSecretKey); + + int result = createSimplePublisher.send(PARTITION_KEY, json); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.debug("Failed during sleep after sending the message.", e); + } + + logger.debug("After sending notification data to topic {}. result is {}", topicName, result); + + } catch (IOException | GeneralSecurityException e) { + logger.debug("Failed to send notification {} to topic {} ", data, topicName, e); + + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + response = processError(e); + + writeErrorToLog(response, e.getMessage(), methodName, "send notification"); + + return response; + + } + + logger.debug("Before closing publisher. Maximum timeout is {} seconds.", waitBeforeCloseTimeout); + try { + List<message> messagesInQ = createSimplePublisher.close(waitBeforeCloseTimeout, TimeUnit.SECONDS); + if (messagesInQ != null && false == messagesInQ.isEmpty()) { + logger.debug("Cambria client returned {} non sent messages.", messagesInQ.size()); + response = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, 500); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + writeErrorToLog(response, "closing publisher returned non sent messages", methodName, "send notification"); + } else { + logger.debug("No message left in the queue after closing cambria publisher"); + response = new CambriaErrorResponse(CambriaOperationStatus.OK, 200); + } + } catch (IOException | InterruptedException e) { + logger.debug("Failed to close cambria publisher", e); + response = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, 500); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + writeErrorToLog(response, "closing publisher returned non sent messages", methodName, "send notification"); + } + logger.debug("After closing publisher"); + + return response; + + } + + public CambriaErrorResponse getApiKey(String server, String apiKey) { + + CambriaErrorResponse response = null; + + List<String> hostSet = new ArrayList<>(); + hostSet.add(server); + CambriaIdentityManager createIdentityManager = null; + try { + createIdentityManager = new IdentityManagerBuilder().usingHosts(hostSet).build(); + createIdentityManager.getApiKey(apiKey); + response = new CambriaErrorResponse(CambriaOperationStatus.OK, 200); + + } catch (HttpException | IOException | CambriaApiException | GeneralSecurityException e) { + logger.debug("Failed to fetch api key {} from server ", apiKey, server, e); + + response = processError(e); + + } + + return response; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DeConfigurationStatus.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DeConfigurationStatus.java new file mode 100644 index 0000000000..5e4c08275f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DeConfigurationStatus.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public enum DeConfigurationStatus { + + OK(""), MISSING_CONFIGURATION(""); + + private String description; + + DeConfigurationStatus(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngine.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngine.java new file mode 100644 index 0000000000..6cb31c8cf2 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngine.java @@ -0,0 +1,367 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.util.YamlToObjectConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("distributionEngine") +public class DistributionEngine implements IDistributionEngine { + + public static final Pattern FQDN_PATTERN = Pattern.compile("^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]))*(:[0-9]{2,4})*$", Pattern.CASE_INSENSITIVE); + + @javax.annotation.Resource + private ComponentsUtils componentUtils; + + @javax.annotation.Resource + private DistributionNotificationSender distributionNotificationSender; + + @javax.annotation.Resource + private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder; + + @javax.annotation.Resource + private DistributionEngineClusterHealth distributionEngineClusterHealth; + + private static Logger logger = LoggerFactory.getLogger(DistributionEngine.class.getName()); + + private Map<String, DistributionEngineInitTask> envNamePerInitTask = new HashMap<String, DistributionEngineInitTask>(); + private Map<String, DistributionEnginePollingTask> envNamePerPollingTask = new HashMap<String, DistributionEnginePollingTask>(); + + private Map<String, AtomicBoolean> envNamePerStatus = new HashMap<String, AtomicBoolean>(); + + @Override + public boolean isActive() { + + if (true == envNamePerInitTask.isEmpty()) { + return false; + } + + for (DistributionEngineInitTask task : envNamePerInitTask.values()) { + boolean active = task.isActive(); + if (active == false) { + return false; + } + } + return true; + } + + @PostConstruct + private void init() { + + logger.trace("Enter init method of DistributionEngine"); + + DistributionEngineConfiguration distributionEngineConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + + boolean startDistributionEngine = distributionEngineConfiguration.isStartDistributionEngine(); + logger.debug("Distribution engine activation parameter is {}", startDistributionEngine); + if (false == startDistributionEngine) { + logger.info("The disribution engine is disabled"); + + this.distributionEngineClusterHealth.setHealthCheckUebIsDisabled(); + + return; + } + + boolean isValidConfig = validateConfiguration(distributionEngineConfiguration); + + if (false == isValidConfig) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, DistributionEngineInitTask.INIT_DISTRIBUTION_ENGINE_FLOW, "validate distribution configuration in init phase"); + BeEcompErrorManager.getInstance().logBeUebSystemError(DistributionEngineInitTask.INIT_DISTRIBUTION_ENGINE_FLOW, "validate distribution configuration in init phase"); + + this.distributionEngineClusterHealth.setHealthCheckUebConfigurationError(); + return; + } + + List<String> environments = distributionEngineConfiguration.getEnvironments(); + + for (String envName : environments) { + + DistributionEnginePollingTask distributionEnginePollingTask = new DistributionEnginePollingTask(distributionEngineConfiguration, envName, componentUtils, distributionEngineClusterHealth); + + logger.debug("Init task for environment {}", envName); + + AtomicBoolean status = new AtomicBoolean(false); + envNamePerStatus.put(envName, status); + DistributionEngineInitTask distributionEngineInitTask = new DistributionEngineInitTask(0l, distributionEngineConfiguration, envName, status, componentUtils, distributionEnginePollingTask); + distributionEngineInitTask.startTask(); + envNamePerInitTask.put(envName, distributionEngineInitTask); + envNamePerPollingTask.put(envName, distributionEnginePollingTask); + } + + logger.debug("Init UEB health check"); + distributionEngineClusterHealth.startHealthCheckTask(envNamePerStatus); + + logger.trace("Exit init method of DistributionEngine"); + + } + + @PreDestroy + public void shutdown() { + logger.info("distribution engine shutdown - start"); + if (envNamePerInitTask != null) { + for (DistributionEngineInitTask task : envNamePerInitTask.values()) { + task.destroy(); + } + } + if (envNamePerPollingTask != null) { + for (DistributionEnginePollingTask task : envNamePerPollingTask.values()) { + task.destroy(); + } + } + + } + + /** + * validate mandatory configuration parameters received + * + * @param deConfiguration + * @return + */ + protected boolean validateConfiguration(DistributionEngineConfiguration deConfiguration) { + + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + boolean result = true; + result = isValidServers(deConfiguration.getUebServers(), methodName, "uebServers") && result; + result = isValidParam(deConfiguration.getEnvironments(), methodName, "environments") && result; + result = isValidParam(deConfiguration.getUebPublicKey(), methodName, "uebPublicKey") && result; + result = isValidParam(deConfiguration.getUebSecretKey(), methodName, "uebSecretKey") && result; + result = isValidParam(deConfiguration.getDistributionNotifTopicName(), methodName, "distributionNotifTopicName") && result; + result = isValidParam(deConfiguration.getDistributionStatusTopicName(), methodName, "distributionStatusTopicName") && result; + result = isValidObject(deConfiguration.getCreateTopic(), methodName, "createTopic") && result; + result = isValidObject(deConfiguration.getDistributionStatusTopic(), methodName, "distributionStatusTopic") && result; + result = isValidObject(deConfiguration.getInitMaxIntervalSec(), methodName, "initMaxIntervalSec") && result; + result = isValidObject(deConfiguration.getInitRetryIntervalSec(), methodName, "initRetryIntervalSec") && result; + result = isValidParam(deConfiguration.getDistributionStatusTopic().getConsumerId(), methodName, "consumerId") && result; + result = isValidParam(deConfiguration.getDistributionStatusTopic().getConsumerGroup(), methodName, "consumerGroup") && result; + result = isValidObject(deConfiguration.getDistributionStatusTopic().getFetchTimeSec(), methodName, "fetchTimeSec") && result; + result = isValidObject(deConfiguration.getDistributionStatusTopic().getPollingIntervalSec(), methodName, "pollingIntervalSec") && result; + + return result; + } + + private boolean isValidServers(List<String> uebServers, String methodName, String paramName) { + + if (uebServers == null || uebServers.size() == 0) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingConfigurationError, methodName, paramName); + BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName); + return false; + } + + if (uebServers.size() < 2) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeConfigurationInvalidListSizeError, methodName, paramName, "2"); + BeEcompErrorManager.getInstance().logBeConfigurationInvalidListSizeError(methodName, paramName, 2); + return false; + } + + for (String serverFqdn : uebServers) { + if (false == isValidFqdn(serverFqdn)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidConfigurationError, methodName, paramName, serverFqdn); + BeEcompErrorManager.getInstance().logBeInvalidConfigurationError(methodName, paramName, serverFqdn); + return false; + } + } + + return true; + } + + private boolean isValidFqdn(String serverFqdn) { + + try { + Matcher matcher = FQDN_PATTERN.matcher(serverFqdn); + return matcher.matches(); + + } catch (Exception e) { + logger.debug("Failed to match value of address {}", serverFqdn, e); + return false; + } + + } + + private boolean isEmptyParam(String param) { + + if (param == null || true == param.isEmpty()) { + return true; + } + + return false; + } + + private boolean isValidParam(String paramValue, String methodName, String paramName) { + + if (isEmptyParam(paramValue)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingConfigurationError, methodName, paramName); + BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName); + return false; + } + return true; + + } + + private boolean isValidParam(List<String> paramValue, String methodName, String paramName) { + + if (isEmptyList(paramValue)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingConfigurationError, methodName, paramName); + BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName); + return false; + } + return true; + + } + + private boolean isValidObject(Object paramValue, String methodName, String paramName) { + + if (paramValue == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingConfigurationError, methodName, paramName); + BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName); + return false; + } + return true; + + } + + private boolean isEmptyList(List<String> list) { + if (list == null || true == list.isEmpty()) { + return true; + } + return false; + } + + private String getEnvironmentErrorDescription(StorageOperationStatus status) { + + switch (status) { + case DISTR_ENVIRONMENT_NOT_AVAILABLE: + return "environment is unavailable"; + case DISTR_ENVIRONMENT_NOT_FOUND: + return "environment is not configured in our system"; + case DISTR_ENVIRONMENT_SENT_IS_INVALID: + return "environment name is invalid"; + + default: + return "unkhown"; + + } + } + + public StorageOperationStatus isEnvironmentAvailable(String envName) { + + if (envName == null || true == envName.isEmpty()) { + + return StorageOperationStatus.DISTR_ENVIRONMENT_SENT_IS_INVALID; + } + + AtomicBoolean status = envNamePerStatus.get(envName); + if (status == null) { + return StorageOperationStatus.DISTR_ENVIRONMENT_NOT_FOUND; + } + + if (false == status.get()) { + return StorageOperationStatus.DISTR_ENVIRONMENT_NOT_AVAILABLE; + } + return StorageOperationStatus.OK; + } + + public StorageOperationStatus isEnvironmentAvailable() { + + String envName = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getEnvironments().get(0); + + return isEnvironmentAvailable(envName); + } + + @Override + public void disableEnvironment(String envName) { + // TODO disable tasks + AtomicBoolean status = envNamePerStatus.get(envName); + status.set(false); + } + + @Override + public StorageOperationStatus notifyService(String distributionId, Service service, INotificationData notificationData, String envName, String userId, String modifierName) { + + if (logger.isDebugEnabled()) { + logger.debug("Received notify service request. distributionId = {}, serviceUuid = {}, serviceUid = {}, envName = {}, userId = {}, modifierName {}", distributionId, service.getUUID(), service.getUniqueId(), envName, userId, modifierName); + } + + DistributionEngineConfiguration deConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + + String distributionNotifTopicName = deConfiguration.getDistributionNotifTopicName(); + String topicName = DistributionEngineInitTask.buildTopicName(distributionNotifTopicName, envName); + + StorageOperationStatus sendNotification = distributionNotificationSender.sendNotification(topicName, distributionId, deConfiguration, envName, notificationData, service, userId, modifierName); + + logger.debug("Finish notifyService. status is {}", sendNotification); + + return sendNotification; + } + + @Override + public Either<INotificationData, StorageOperationStatus> isReadyForDistribution(Service service, String distributionId, String envName) { + StorageOperationStatus status = isEnvironmentAvailable(envName); + if (status != StorageOperationStatus.OK) { + String envErrorDec = getEnvironmentErrorDescription(status); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, DistributionNotificationSender.DISTRIBUTION_NOTIFICATION_SENDING, + "Environment name " + envName + " is not available. Reason : " + envErrorDec); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(DistributionNotificationSender.DISTRIBUTION_NOTIFICATION_SENDING, "Environment name " + envName + " is not available. Reason : " + envErrorDec); + return Either.right(status); + } + + Either<Boolean, StorageOperationStatus> isServiceContainsDeploymentArtifactsStatus = serviceDistributionArtifactsBuilder.isServiceContainsDeploymentArtifacts(service); + if (isServiceContainsDeploymentArtifactsStatus.isRight()) { + StorageOperationStatus operationStatus = isServiceContainsDeploymentArtifactsStatus.right().value(); + return Either.right(operationStatus); + } else { + Boolean isDeploymentArtifactExists = isServiceContainsDeploymentArtifactsStatus.left().value(); + if (isDeploymentArtifactExists == null || isDeploymentArtifactExists.booleanValue() == false) { + return Either.right(StorageOperationStatus.DISTR_ARTIFACT_NOT_FOUND); + } + } + + INotificationData value = serviceDistributionArtifactsBuilder.buildResourceInstanceForDistribution(service, distributionId); + value = serviceDistributionArtifactsBuilder.buildServiceForDistribution(value, service); + + return Either.left(value); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngineClusterHealth.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngineClusterHealth.java new file mode 100644 index 0000000000..a3d0362c61 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngineClusterHealth.java @@ -0,0 +1,356 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.common.api.HealthCheckInfo; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckComponent; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component("distribution-engine-cluster-health") +public class DistributionEngineClusterHealth { + + protected static String UEB_HEALTH_LOG_CONTEXT = "ueb.healthcheck"; + + private static Logger healthLogger = LoggerFactory.getLogger(UEB_HEALTH_LOG_CONTEXT); + + private static final String UEB_HEALTH_CHECK_STR = "uebHealthCheck"; + + boolean lastHealthState = false; + + Object lockOject = new Object(); + + private long reconnectInterval = 5; + + private long healthCheckReadTimeout = 20; + + private static Logger logger = LoggerFactory.getLogger(DistributionEngineClusterHealth.class.getName()); + + private List<String> uebServers = null; + + private String publicApiKey = null; + + public enum HealthCheckInfoResult { + + OK(new HealthCheckInfo(HealthCheckComponent.DE, HealthCheckStatus.UP, null, ClusterStatusDescription.OK.getDescription())), UNAVAILABLE( + new HealthCheckInfo(HealthCheckComponent.DE, HealthCheckStatus.DOWN, null, ClusterStatusDescription.UNAVAILABLE.getDescription())), NOT_CONFIGURED( + new HealthCheckInfo(HealthCheckComponent.DE, HealthCheckStatus.DOWN, null, ClusterStatusDescription.NOT_CONFIGURED.getDescription())), DISABLED( + new HealthCheckInfo(HealthCheckComponent.DE, HealthCheckStatus.DOWN, null, ClusterStatusDescription.DISABLED.getDescription())); + + private HealthCheckInfo healthCheckInfo; + + HealthCheckInfoResult(HealthCheckInfo healthCheckInfo) { + this.healthCheckInfo = healthCheckInfo; + } + + public HealthCheckInfo getHealthCheckInfo() { + return healthCheckInfo; + } + + } + + private HealthCheckInfo healthCheckInfo = HealthCheckInfoResult.UNAVAILABLE.getHealthCheckInfo(); + + private Map<String, AtomicBoolean> envNamePerStatus = null; + + private ScheduledFuture<?> scheduledFuture = null; + + ScheduledExecutorService healthCheckScheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "UEB-Health-Check-Task"); + } + }); + + HealthCheckScheduledTask healthCheckScheduledTask = null; + + public enum ClusterStatusDescription { + + OK("OK"), UNAVAILABLE("U-EB cluster is not available"), NOT_CONFIGURED("U-EB cluster is not configured"), DISABLED("DE is disabled in configuration"); + + private String desc; + + ClusterStatusDescription(String desc) { + this.desc = desc; + } + + public String getDescription() { + return desc; + } + + } + + /** + * Health Check Task Scheduler. + * + * It schedules a task which send a apiKey get query towards the UEB servers. In case a query to the first UEB server is failed, then a second query is sent to the next UEB server. + * + * + * @author esofer + * + */ + public class HealthCheckScheduledTask implements Runnable { + + List<UebHealthCheckCall> healthCheckCalls = new ArrayList<>(); + + public HealthCheckScheduledTask(List<String> uebServers) { + + logger.debug("Create health check calls for servers {}", uebServers); + if (uebServers != null) { + for (String server : uebServers) { + healthCheckCalls.add(new UebHealthCheckCall(server, publicApiKey)); + } + } + } + + @Override + public void run() { + + healthLogger.trace("Executing UEB Health Check Task - Start"); + + boolean healthStatus = verifyAtLeastOneEnvIsUp(); + + if (true == healthStatus) { + boolean queryUebStatus = queryUeb(); + if (queryUebStatus == lastHealthState) { + return; + } + + synchronized (lockOject) { + if (queryUebStatus != lastHealthState) { + logger.trace("UEB Health State Changed to {}. Issuing alarm / recovery alarm...", healthStatus); + lastHealthState = queryUebStatus; + logAlarm(lastHealthState); + if (true == queryUebStatus) { + healthCheckInfo = HealthCheckInfoResult.OK.getHealthCheckInfo(); + } else { + healthCheckInfo = HealthCheckInfoResult.UNAVAILABLE.getHealthCheckInfo(); + } + } + } + } else { + healthLogger.trace("Not all UEB Environments are up"); + } + + } + + /** + * verify that at least one environment is up. + * + */ + private boolean verifyAtLeastOneEnvIsUp() { + + boolean healthStatus = false; + + if (envNamePerStatus != null) { + Collection<AtomicBoolean> values = envNamePerStatus.values(); + if (values != null) { + for (AtomicBoolean status : values) { + if (true == status.get()) { + healthStatus = true; + break; + } + } + } + } + + return healthStatus; + } + + /** + * executor for the query itself + */ + ExecutorService healthCheckExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "UEB-Health-Check-Thread"); + } + }); + + /** + * go all UEB servers and send a get apiKeys query. In case a query is succeed, no query is sent to the rest of UEB servers. + * + * + * @return + */ + private boolean queryUeb() { + + Boolean result = false; + int retryNumber = 1; + for (UebHealthCheckCall healthCheckCall : healthCheckCalls) { + try { + + healthLogger.debug("Before running Health Check retry query number {} towards UEB server {}", retryNumber, healthCheckCall.getServer()); + + Future<Boolean> future = healthCheckExecutor.submit(healthCheckCall); + result = future.get(healthCheckReadTimeout, TimeUnit.SECONDS); + + healthLogger.debug("After running Health Check retry query number {} towards UEB server {}. Result is {}", retryNumber, healthCheckCall.getServer(), result); + + if (result != null && true == result.booleanValue()) { + break; + } + + } catch (Exception e) { + String message = e.getMessage(); + if (message == null) { + message = e.getClass().getName(); + } + healthLogger.debug("Error occured during running Health Check retry query towards UEB server {}. Result is {}", healthCheckCall.getServer(), message); + } + retryNumber++; + + } + + return result; + + } + + public List<UebHealthCheckCall> getHealthCheckCalls() { + return healthCheckCalls; + } + + } + + @PostConstruct + private void init() { + + logger.trace("Enter init method of DistributionEngineClusterHealth"); + + Long reconnectIntervalConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getUebHealthCheckReconnectIntervalInSeconds(); + if (reconnectIntervalConfig != null) { + reconnectInterval = reconnectIntervalConfig.longValue(); + } + Long healthCheckReadTimeoutConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getUebHealthCheckReadTimeout(); + if (healthCheckReadTimeoutConfig != null) { + healthCheckReadTimeout = healthCheckReadTimeoutConfig.longValue(); + } + + DistributionEngineConfiguration distributionEngineConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + + this.uebServers = distributionEngineConfiguration.getUebServers(); + this.publicApiKey = distributionEngineConfiguration.getUebPublicKey(); + + this.healthCheckScheduledTask = new HealthCheckScheduledTask(this.uebServers); + + logger.trace("Exit init method of DistributionEngineClusterHealth"); + + } + + @PreDestroy + private void destroy() { + + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + scheduledFuture = null; + } + + if (healthCheckScheduler != null) { + healthCheckScheduler.shutdown(); + } + + } + + /** + * Start health check task. + * + * @param envNamePerStatus + * @param startTask + */ + public void startHealthCheckTask(Map<String, AtomicBoolean> envNamePerStatus, boolean startTask) { + this.envNamePerStatus = envNamePerStatus; + + if (startTask == true && this.scheduledFuture == null) { + this.scheduledFuture = this.healthCheckScheduler.scheduleAtFixedRate(healthCheckScheduledTask, 0, reconnectInterval, TimeUnit.SECONDS); + } + } + + public void startHealthCheckTask(Map<String, AtomicBoolean> envNamePerStatus) { + startHealthCheckTask(envNamePerStatus, true); + } + + private void logAlarm(boolean lastHealthState) { + if (lastHealthState == true) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeHealthCheckRecovery, UEB_HEALTH_CHECK_STR); + BeEcompErrorManager.getInstance().logBeHealthCheckUebClusterRecovery(UEB_HEALTH_CHECK_STR); + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeHealthCheckError, UEB_HEALTH_CHECK_STR); + BeEcompErrorManager.getInstance().logBeHealthCheckUebClusterError(UEB_HEALTH_CHECK_STR); + } + } + + public HealthCheckInfo getHealthCheckInfo() { + return healthCheckInfo; + } + + /** + * change the health check to DISABLE + */ + public void setHealthCheckUebIsDisabled() { + healthCheckInfo = HealthCheckInfoResult.DISABLED.getHealthCheckInfo(); + } + + /** + * change the health check to NOT CONFGIURED + */ + public void setHealthCheckUebConfigurationError() { + healthCheckInfo = HealthCheckInfoResult.NOT_CONFIGURED.getHealthCheckInfo(); + } + + public void setHealthCheckOkAndReportInCaseLastStateIsDown() { + + if (lastHealthState == true) { + return; + } + synchronized (lockOject) { + if (lastHealthState == false) { + logger.debug("Going to update health check state to available"); + lastHealthState = true; + healthCheckInfo = HealthCheckInfoResult.OK.getHealthCheckInfo(); + logAlarm(lastHealthState); + } + } + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngineInitTask.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngineInitTask.java new file mode 100644 index 0000000000..1eeaa1229e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEngineInitTask.java @@ -0,0 +1,293 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.be.distribution.api.client.CambriaOperationStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class DistributionEngineInitTask implements Runnable { + + public static final String INIT_DISTRIBUTION_ENGINE_FLOW = "initDistributionEngine"; + public static final String ALREADY_EXISTS = "ALREADY_EXISTS"; + public static final String CONSUMER = "CONSUMER"; + public static final String PRODUCER = "PRODUCER"; + public static final String CREATED = "CREATED"; + public static final String FAILED = "FAILED"; + public static final Integer HTTP_OK = 200; + + private Long delayBeforeStartFlow = 0l; + private DistributionEngineConfiguration deConfiguration; + private String envName; + private long retryInterval; + private long currentRetryInterval; + private long maxInterval; + // private boolean active = false; + boolean maximumRetryInterval = false; + private AtomicBoolean status = null; + ComponentsUtils componentsUtils = null; + DistributionEnginePollingTask distributionEnginePollingTask = null; + + private CambriaHandler cambriaHandler = new CambriaHandler(); + + public DistributionEngineInitTask(Long delayBeforeStartFlow, DistributionEngineConfiguration deConfiguration, String envName, AtomicBoolean status, ComponentsUtils componentsUtils, DistributionEnginePollingTask distributionEnginePollingTask) { + super(); + this.delayBeforeStartFlow = delayBeforeStartFlow; + this.deConfiguration = deConfiguration; + this.envName = envName; + this.retryInterval = deConfiguration.getInitRetryIntervalSec(); + this.currentRetryInterval = retryInterval; + this.maxInterval = deConfiguration.getInitMaxIntervalSec(); + this.status = status; + this.componentsUtils = componentsUtils; + this.distributionEnginePollingTask = distributionEnginePollingTask; + } + + private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); + + private static Logger logger = LoggerFactory.getLogger(DistributionEngineInitTask.class.getName()); + + ScheduledFuture<?> scheduledFuture = null; + + public void startTask() { + if (scheduledExecutorService != null) { + Integer retryInterval = deConfiguration.getInitRetryIntervalSec(); + logger.debug("Start Distribution Engine init task. retry interval {} seconds, delay before first run {} seconds", retryInterval, delayBeforeStartFlow); + this.scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(this, delayBeforeStartFlow, retryInterval, TimeUnit.SECONDS); + + } + } + + public void restartTask() { + + this.stopTask(); + + logger.debug("Start Distribution Engine init task. next run in {} seconds", this.currentRetryInterval); + + long lastCurrentInterval = currentRetryInterval; + incrementRetryInterval(); + + this.scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(this, lastCurrentInterval, this.currentRetryInterval, TimeUnit.SECONDS); + + } + + protected void incrementRetryInterval() { + if (currentRetryInterval < maxInterval) { + currentRetryInterval *= 2; + if (currentRetryInterval > maxInterval) { + setMaxRetryInterval(); + } + } else { + setMaxRetryInterval(); + } + } + + private void setMaxRetryInterval() { + currentRetryInterval = maxInterval; + maximumRetryInterval = true; + logger.debug("Set next retry init interval to {}", maxInterval); + } + + public void stopTask() { + if (scheduledFuture != null) { + boolean result = scheduledFuture.cancel(true); + logger.debug("Stop reinit task. result = {}", result); + if (false == result) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, INIT_DISTRIBUTION_ENGINE_FLOW, "try to stop the reinit task"); + BeEcompErrorManager.getInstance().logBeUebSystemError(INIT_DISTRIBUTION_ENGINE_FLOW, "try to stop the reinit task"); + } + scheduledFuture = null; + } + } + + public void destroy() { + this.stopTask(); + if (scheduledExecutorService != null) { + scheduledExecutorService.shutdown(); + } + } + + @Override + public void run() { + + boolean result = false; + result = initFlow(); + + if (true == result) { + this.stopTask(); + this.status.set(true); + if (this.distributionEnginePollingTask != null) { + String topicName = buildTopicName(deConfiguration.getDistributionStatusTopicName(), envName); + logger.debug("start polling distribution status topic {}", topicName); + this.distributionEnginePollingTask.startTask(topicName); + } + } else { + if (false == maximumRetryInterval) { + this.restartTask(); + } + } + } + + /** + * run initialization flow + * + * @return + */ + public boolean initFlow() { + + logger.trace("Start init flow for environment {}", this.envName); + + Set<String> topicsList = null; + Either<Set<String>, CambriaErrorResponse> getTopicsRes = null; + + getTopicsRes = cambriaHandler.getTopics(deConfiguration.getUebServers()); + if (getTopicsRes.isRight()) { + CambriaErrorResponse status = getTopicsRes.right().value(); + if (status.getOperationStatus() == CambriaOperationStatus.NOT_FOUND) { + topicsList = new HashSet<>(); + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, INIT_DISTRIBUTION_ENGINE_FLOW, "try retrieve list of topics from U-EB server"); + + BeEcompErrorManager.getInstance().logBeUebSystemError(INIT_DISTRIBUTION_ENGINE_FLOW, "try retrieve list of topics from U-EB server"); + + return false; + } + } else { + topicsList = getTopicsRes.left().value(); + } + + String notificationTopic = buildTopicName(deConfiguration.getDistributionNotifTopicName(), this.envName); + logger.debug("Going to handle topic {}", notificationTopic); + + boolean status = createTopicIfNotExists(topicsList, notificationTopic); + if (false == status) { + return false; + } + + CambriaErrorResponse registerProducerStatus = registerToTopic(notificationTopic, SubscriberTypeEnum.PRODUCER); + + CambriaOperationStatus createStatus = registerProducerStatus.getOperationStatus(); + + if (createStatus != CambriaOperationStatus.OK) { + return false; + } + + String statusTopic = buildTopicName(deConfiguration.getDistributionStatusTopicName(), this.envName); + logger.debug("Going to handle topic {}", statusTopic); + status = createTopicIfNotExists(topicsList, statusTopic); + if (false == status) { + return false; + } + + CambriaErrorResponse registerConcumerStatus = registerToTopic(statusTopic, SubscriberTypeEnum.CONSUMER); + + if (registerConcumerStatus.getOperationStatus() != CambriaOperationStatus.OK) { + return false; + } + + return true; + } + + private CambriaErrorResponse registerToTopic(String topicName, SubscriberTypeEnum subscriberType) { + CambriaErrorResponse registerStatus = cambriaHandler.registerToTopic(deConfiguration.getUebServers(), topicName, deConfiguration.getUebPublicKey(), deConfiguration.getUebSecretKey(), deConfiguration.getUebPublicKey(), subscriberType); + + String role = CONSUMER; + if (subscriberType == SubscriberTypeEnum.PRODUCER) { + role = PRODUCER; + } + auditRegistration(topicName, registerStatus, role); + return registerStatus; + } + + private void auditRegistration(String notificationTopic, CambriaErrorResponse registerProducerStatus, String role) { + if (componentsUtils != null) { + Integer httpCode = registerProducerStatus.getHttpCode(); + String httpCodeStr = String.valueOf(httpCode); + this.componentsUtils.auditDistributionEngine(AuditingActionEnum.ADD_KEY_TO_TOPIC_ACL, this.envName, notificationTopic, role, deConfiguration.getUebPublicKey(), httpCodeStr); + } + } + + private boolean createTopicIfNotExists(Set<String> topicsList, String topicName) { + + if (topicsList.contains(topicName)) { + if (componentsUtils != null) { + this.componentsUtils.auditDistributionEngine(AuditingActionEnum.CREATE_DISTRIBUTION_TOPIC, this.envName, topicName, null, null, ALREADY_EXISTS); + } + return true; + } + + CambriaErrorResponse createDistribTopicStatus = cambriaHandler.createTopic(deConfiguration.getUebServers(), deConfiguration.getUebPublicKey(), deConfiguration.getUebSecretKey(), topicName, deConfiguration.getCreateTopic().getPartitionCount(), + deConfiguration.getCreateTopic().getReplicationCount()); + + CambriaOperationStatus status = createDistribTopicStatus.getOperationStatus(); + if (status == CambriaOperationStatus.TOPIC_ALREADY_EXIST) { + if (componentsUtils != null) { + this.componentsUtils.auditDistributionEngine(AuditingActionEnum.CREATE_DISTRIBUTION_TOPIC, this.envName, topicName, null, null, ALREADY_EXISTS); + } + } else if (status == CambriaOperationStatus.OK) { + if (componentsUtils != null) { + this.componentsUtils.auditDistributionEngine(AuditingActionEnum.CREATE_DISTRIBUTION_TOPIC, this.envName, topicName, null, null, CREATED); + } + } else { + if (componentsUtils != null) { + this.componentsUtils.auditDistributionEngine(AuditingActionEnum.CREATE_DISTRIBUTION_TOPIC, this.envName, topicName, null, null, FAILED); + } + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, INIT_DISTRIBUTION_ENGINE_FLOW, "try to create topic " + topicName); + + BeEcompErrorManager.getInstance().logBeUebSystemError(INIT_DISTRIBUTION_ENGINE_FLOW, "try to create topic " + topicName); + + return false; + } + + return true; + } + + public static String buildTopicName(String topicName, String environment) { + return topicName + "-" + environment.toUpperCase(); + } + + public boolean isActive() { + return this.status.get(); + } + + public long getCurrentRetryInterval() { + return currentRetryInterval; + } + + protected void setCambriaHandler(CambriaHandler cambriaHandler) { + this.cambriaHandler = cambriaHandler; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEnginePollingTask.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEnginePollingTask.java new file mode 100644 index 0000000000..fc7c473d6b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionEnginePollingTask.java @@ -0,0 +1,207 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration.DistributionStatusTopicConfig; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.att.nsa.cambria.client.CambriaConsumer; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import fj.data.Either; + +public class DistributionEnginePollingTask implements Runnable { + + public static final String DISTRIBUTION_STATUS_POLLING = "distributionEngineStatusPolling"; + + private String topicName; + private ComponentsUtils componentUtils; + private int fetchTimeoutInSec = 15; + private int pollingIntervalInSec; + private String consumerId; + private String consumerGroup; + private DistributionEngineConfiguration distributionEngineConfiguration; + + private CambriaHandler cambriaHandler = new CambriaHandler(); + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + private ScheduledExecutorService scheduledPollingService = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("TopicPollingThread-%d").build()); + + private static Logger logger = LoggerFactory.getLogger(DistributionEnginePollingTask.class.getName()); + + ScheduledFuture<?> scheduledFuture = null; + private CambriaConsumer cambriaConsumer = null; + + private DistributionEngineClusterHealth distributionEngineClusterHealth = null; + + public DistributionEnginePollingTask(DistributionEngineConfiguration distributionEngineConfiguration, String envName, ComponentsUtils componentUtils, DistributionEngineClusterHealth distributionEngineClusterHealth) { + + this.componentUtils = componentUtils; + this.distributionEngineConfiguration = distributionEngineConfiguration; + DistributionStatusTopicConfig statusConfig = distributionEngineConfiguration.getDistributionStatusTopic(); + this.pollingIntervalInSec = statusConfig.getPollingIntervalSec(); + this.fetchTimeoutInSec = statusConfig.getFetchTimeSec(); + this.consumerGroup = statusConfig.getConsumerGroup(); + this.consumerId = statusConfig.getConsumerId(); + this.distributionEngineClusterHealth = distributionEngineClusterHealth; + } + + public void startTask(String topicName) { + + this.topicName = topicName; + logger.debug("start task for polling topic {}", topicName); + if (fetchTimeoutInSec < 15) { + logger.warn("fetchTimeout value should be greater or equal to 15 sec. use default"); + fetchTimeoutInSec = 15; + } + try { + cambriaConsumer = cambriaHandler.createConsumer(distributionEngineConfiguration.getUebServers(), topicName, distributionEngineConfiguration.getUebPublicKey(), distributionEngineConfiguration.getUebSecretKey(), consumerId, consumerGroup, + fetchTimeoutInSec * 1000); + + if (scheduledPollingService != null) { + logger.debug("Start Distribution Engine polling task. polling interval {} seconds", pollingIntervalInSec); + scheduledFuture = scheduledPollingService.scheduleAtFixedRate(this, 0, pollingIntervalInSec, TimeUnit.SECONDS); + + } + } catch (Exception e) { + logger.debug("unexpected error occured", e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(methodName, e.getMessage()); + } + } + + public void stopTask() { + if (scheduledFuture != null) { + boolean result = scheduledFuture.cancel(true); + logger.debug("Stop polling task. result = {}", result); + if (false == result) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, DISTRIBUTION_STATUS_POLLING, "try to stop the polling task"); + BeEcompErrorManager.getInstance().logBeUebSystemError(DISTRIBUTION_STATUS_POLLING, "try to stop the polling task"); + } + scheduledFuture = null; + } + if (cambriaConsumer != null) { + logger.debug("close consumer"); + cambriaHandler.closeConsumer(cambriaConsumer); + } + + } + + public void destroy() { + this.stopTask(); + shutdownExecutor(); + } + + @Override + public void run() { + logger.trace("run() method. polling queue {}", topicName); + + try { + // init error + if (cambriaConsumer == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, DISTRIBUTION_STATUS_POLLING, "polling task was not initialized properly"); + BeEcompErrorManager.getInstance().logBeUebSystemError(DISTRIBUTION_STATUS_POLLING, "polling task was not initialized properly"); + stopTask(); + return; + } + + Either<Iterable<String>, CambriaErrorResponse> fetchResult = cambriaHandler.fetchFromTopic(cambriaConsumer); + // fetch error + if (fetchResult.isRight()) { + CambriaErrorResponse errorResponse = fetchResult.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, DISTRIBUTION_STATUS_POLLING, "failed to fetch messages from topic " + topicName + " error: " + fetchResult.right().value()); + BeEcompErrorManager.getInstance().logBeUebSystemError(DISTRIBUTION_STATUS_POLLING, "failed to fetch messages from topic " + topicName + " error: " + fetchResult.right().value()); + + // TODO: if status== internal error (connection problem) change + // state to inactive + // in next try, if succeed - change to active + return; + } + + // success + Iterable<String> messages = fetchResult.left().value(); + for (String message : messages) { + logger.trace("received message {}", message); + try { + DistributionStatusNotification notification = gson.fromJson(message, DistributionStatusNotification.class); + componentUtils.auditDistributionStatusNotification(AuditingActionEnum.DISTRIBUTION_STATUS, notification.getDistributionID(), notification.getConsumerID(), topicName, notification.getArtifactURL(), + String.valueOf(notification.getTimestamp()), notification.getStatus().name(), notification.getErrorReason()); + + distributionEngineClusterHealth.setHealthCheckOkAndReportInCaseLastStateIsDown(); + + } catch (Exception e) { + logger.debug("failed to convert message to object", e); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUebSystemError, DISTRIBUTION_STATUS_POLLING, "failed to parse message " + message + " from topic " + topicName + " error: " + fetchResult.right().value()); + BeEcompErrorManager.getInstance().logBeUebSystemError(DISTRIBUTION_STATUS_POLLING, "failed to parse message " + message + " from topic " + topicName + " error: " + fetchResult.right().value()); + } + + } + } catch (Exception e) { + logger.debug("unexpected error occured", e); + String methodName = new Object() { + }.getClass().getEnclosingMethod().getName(); + + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, methodName, e.getMessage()); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(methodName, e.getMessage()); + } + + } + + private void shutdownExecutor() { + if (scheduledPollingService == null) + return; + + scheduledPollingService.shutdown(); // Disable new tasks from being + // submitted + try { + // Wait a while for existing tasks to terminate + if (!scheduledPollingService.awaitTermination(60, TimeUnit.SECONDS)) { + scheduledPollingService.shutdownNow(); // Cancel currently + // executing tasks + // Wait a while for tasks to respond to being cancelled + if (!scheduledPollingService.awaitTermination(60, TimeUnit.SECONDS)) + logger.debug("Pool did not terminate"); + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + scheduledPollingService.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionNotificationSender.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionNotificationSender.java new file mode 100644 index 0000000000..667276db2c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionNotificationSender.java @@ -0,0 +1,127 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; + +import javax.annotation.PreDestroy; + +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration.DistributionNotificationTopicConfig; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.operations.api.IServiceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.util.ThreadLocalsHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component("distributionNotificationSender") +public class DistributionNotificationSender { + + protected static final String DISTRIBUTION_NOTIFICATION_SENDING = "distributionNotificationSending"; + + private static Logger logger = LoggerFactory.getLogger(DistributionNotificationSender.class.getName()); + + // final String BASE_ARTIFACT_URL = "/asdc/v1/catalog/services/%s/%s/"; + // final String RESOURCE_ARTIFACT_URL = BASE_ARTIFACT_URL + // + "resources/%s/%s/artifacts/%s"; + // final String SERVICE_ARTIFACT_URL = BASE_ARTIFACT_URL + "artifacts/%s"; + + @javax.annotation.Resource + InterfaceLifecycleOperation interfaceLifecycleOperation; + + @javax.annotation.Resource + protected IServiceOperation serviceOperation; + + @javax.annotation.Resource + protected ResourceOperation resourceOperation; + + @javax.annotation.Resource + protected ComponentsUtils componentUtils; + + ExecutorService executorService = null; + + CambriaHandler cambriaHandler = new CambriaHandler(); + + NotificationExecutorService notificationExecutorService = new NotificationExecutorService(); + + public DistributionNotificationSender() { + super(); + + DistributionNotificationTopicConfig distributionNotificationTopic = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getDistributionNotificationTopic(); + + executorService = notificationExecutorService.createExcecutorService(distributionNotificationTopic); + } + + @PreDestroy + public void shutdown() { + logger.debug("Going to close notificationExecutorService"); + if (executorService != null) { + + long maxWaitingTime = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getDistributionNotificationTopic().getMaxWaitingAfterSendingSeconds(); + + notificationExecutorService.shutdownAndAwaitTermination(executorService, maxWaitingTime + 1); + } + } + + public StorageOperationStatus sendNotification(String topicName, String distributionId, DistributionEngineConfiguration deConfiguration, String envName, INotificationData notificationData, Service service, String userId, String modifierName) { + + Runnable task = new PublishNotificationRunnable(envName, distributionId, service, notificationData, deConfiguration, topicName, userId, modifierName, cambriaHandler, componentUtils, ThreadLocalsHolder.getUuid()); + try { + executorService.submit(task); + } catch (RejectedExecutionException e) { + logger.warn("Failed to submit task. Number of threads exceeeds", e); + return StorageOperationStatus.OVERLOAD; + } + + return StorageOperationStatus.OK; + } + + /** + * Audit the publishing notification in case of internal server error. + * + * @param topicName + * @param status + * @param distributionId + * @param envName + */ + private void auditDistributionNotificationInternalServerError(String topicName, StorageOperationStatus status, String distributionId, String envName) { + + if (this.componentUtils != null) { + this.componentUtils.auditDistributionNotification(AuditingActionEnum.DISTRIBUTION_NOTIFY, "", " ", "Service", " ", " ", " ", envName, " ", topicName, distributionId, "Error: Internal Server Error. " + status, " "); + } + } + + protected CambriaErrorResponse publishNotification(INotificationData data, DistributionEngineConfiguration deConfiguration, String topicName) { + + CambriaErrorResponse status = cambriaHandler.sendNotification(topicName, deConfiguration.getUebPublicKey(), deConfiguration.getUebSecretKey(), deConfiguration.getUebServers(), data); + + return status; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionStatusNotification.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionStatusNotification.java new file mode 100644 index 0000000000..73a0336361 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionStatusNotification.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public class DistributionStatusNotification { + + String distributionID; + String consumerID; + long timestamp; + String artifactURL; + DistributionStatusNotificationEnum status; + String errorReason; + + public String getDistributionID() { + return distributionID; + } + + public void setDistributionID(String distributionId) { + this.distributionID = distributionId; + } + + public String getConsumerID() { + return consumerID; + } + + public void setConsumerID(String consumerId) { + this.consumerID = consumerId; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public String getArtifactURL() { + return artifactURL; + } + + public void setArtifactURL(String artifactURL) { + this.artifactURL = artifactURL; + } + + public DistributionStatusNotificationEnum getStatus() { + return status; + } + + public void setStatus(DistributionStatusNotificationEnum status) { + this.status = status; + } + + public String getErrorReason() { + return errorReason; + } + + public void setErrorReason(String errorReason) { + this.errorReason = errorReason; + } + + @Override + public String toString() { + return "DistributionStatusNotification [distributionId=" + distributionID + ", consumerId=" + consumerID + ", timestamp=" + timestamp + ", artifactURL=" + artifactURL + ", status=" + status + ", errorReason=" + errorReason + "]"; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionStatusNotificationEnum.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionStatusNotificationEnum.java new file mode 100644 index 0000000000..bd77f3915a --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/DistributionStatusNotificationEnum.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public enum DistributionStatusNotificationEnum { + + DOWNLOAD_OK, DOWNLOAD_ERROR, ALREADY_DOWNLOADED, DEPLOY_OK, DEPLOY_ERROR, ALREADY_DEPLOYED, NOTIFIED, NOT_NOTIFIED +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IArtifactInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IArtifactInfo.java new file mode 100644 index 0000000000..169f4f3efa --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IArtifactInfo.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import org.openecomp.sdc.common.api.ArtifactTypeEnum; + +public interface IArtifactInfo { + + /** Artifact File name */ + String getArtifactName(); + + /** + * Artifact Type.<br> + * Following are valid values : HEAT , DG_XML. <br> + * List of values will be extended in post-1510 releases. + */ + ArtifactTypeEnum getArtifactType(); + + /** + * Relative artifact's URL. Should be used in REST GET API to download the artifact's payload.<br> + * The full artifact URL will be in the following format :<br> + * https://{serverBaseURL}/{resourcePath}<br> + * serverBaseURL - Hostname ( ASDC LB FQDN) + optional port <br> + * resourcePath - "artifactURL" <br> + * Ex : https://asdc.sdc.com/v1/catalog/services/srv1/2.0/resources/aaa/1.0/artifacts/aaa.yml + */ + String getArtifactURL(); + + /** + * Base-64 encoded MD5 checksum of the artifact's payload.<br> + * Should be used for data integrity validation when an artifact's payload is downloaded.<br> + */ + String getArtifactChecksum(); + + /** + * Installation timeout. Used by the orchestrator. + */ + Integer getArtifactTimeout(); + + /** + * Artifact description + */ + String getArtifactDescription(); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IDistributionEngine.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IDistributionEngine.java new file mode 100644 index 0000000000..a27156616b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IDistributionEngine.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; + +import fj.data.Either; + +public interface IDistributionEngine { + + public boolean isActive(); + + public StorageOperationStatus notifyService(String distributionId, Service service, INotificationData notificationData, String envName, String userId, String modifierName); + + public StorageOperationStatus isEnvironmentAvailable(String envName); + + /** + * Currently, it used for tests. For real implementation we need cancel the initialization task and the polling task. + * + * @param envName + */ + public void disableEnvironment(String envName); + + public Either<INotificationData, StorageOperationStatus> isReadyForDistribution(Service service, String distributionId, String envName); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/INotificationData.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/INotificationData.java new file mode 100644 index 0000000000..48f6c42823 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/INotificationData.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.List; + +public interface INotificationData { + /** + * Global Distribution Identifier: UUID generated by ASDC per each distribution activation.<br> + * Generated UUID is compliant with RFC 4122.<br> + * It is a 128-bit value formatted into blocks of hexadecimal digits separated by a hyphen ("-").<br> + * Ex.: AA97B177-9383-4934-8543-0F91A7A02836 + */ + String getDistributionID(); + + /** Logical Service Name. */ + String getServiceName(); + + /** + * Service Version.<br> + * Two dot (".") separated digit blocks.<br> + * Ex. : "2.0" + */ + String getServiceVersion(); + + /** + * Global UUID generated by ASDC per each service version. Generated UUID is compliant with RFC 4122.<br> + * It is a 128-bit value formatted into blocks of hexadecimal digits separated by a hyphen ("-").<br> + * Ex. : AA97B177-9383-4934-8543-0F91A7A02836 + */ + String getServiceUUID(); + + /** + * Service description + */ + String getServiceDescription(); + + /** + * ServiceInvariant UUID + */ + String getServiceInvariantUUID(); + + /** List of the resource instances */ + List<JsonContainerResourceInstance> getResources(); + + /** List of the artifacts */ + List<ArtifactInfoImpl> getServiceArtifacts(); + + void setDistributionID(String distributionId); + + /** Logical Service Name. */ + void setServiceName(String serviceName); + + /** + * Service Version.<br> + * Two dot (".") separated digit blocks.<br> + * Ex. : "2.0" + */ + void setServiceVersion(String serviceVersion); + + /** + * Global UUID generated by ASDC per each service version. Generated UUID is compliant with RFC 4122.<br> + * It is a 128-bit value formatted into blocks of hexadecimal digits separated by a hyphen ("-").<br> + * Ex. : AA97B177-9383-4934-8543-0F91A7A02836 + */ + void setServiceUUID(String serviceUUID); + + /** + * Service Description + */ + void setServiceDescription(String serviceDescription); + + /** + * ServiceInvariant UUID + */ + void setServiceInvariantUUID(String serviceInvariantUuid); + + /** List of the Resource Instances */ + void setResources(List<JsonContainerResourceInstance> resource); + + /** List of the Resource Instances */ + void setServiceArtifacts(List<ArtifactInfoImpl> artifacts); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IResourceArtifactInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IResourceArtifactInfo.java new file mode 100644 index 0000000000..9a77b9f94f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IResourceArtifactInfo.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public interface IResourceArtifactInfo extends IArtifactInfo { + + /** resource name */ + String getResourceName(); + + /** resource version */ + String getResourceVersion(); + + /** + * Global UUID of the resource that specific artifact belongs to.<br> + * It is generated by ASDC per each resource version.<br> + * Generated UUID is compliant with RFC 4122. It is a 128-bit value formatted into blocks of hexadecimal digits separated by a hyphen ("-"). <br> + * Ex.: AA97B177-9383-4934-8543-0F91A7A02836 + */ + String getResourceUUID(); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IServiceArtifactInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IServiceArtifactInfo.java new file mode 100644 index 0000000000..e102f742ac --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/IServiceArtifactInfo.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public interface IServiceArtifactInfo extends IArtifactInfo { + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java new file mode 100644 index 0000000000..25a6f46c90 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.List; + +import org.openecomp.sdc.be.model.ComponentInstance; + +public class JsonContainerResourceInstance { + private String resourceInstanceName, resourceName, resourceVersion, resoucreType, resourceUUID, resourceInvariantUUID; + private List<ArtifactInfoImpl> artifacts; + + public JsonContainerResourceInstance(ComponentInstance resourceInstance, String resourceType, List<ArtifactInfoImpl> artifacts) { + super(); + this.resourceInstanceName = resourceInstance.getName(); + this.resourceName = resourceInstance.getComponentName(); + this.resourceVersion = resourceInstance.getComponentVersion(); + this.resoucreType = resourceType; + this.resourceUUID = resourceInstance.getComponentUid(); + this.artifacts = artifacts; + } + + public JsonContainerResourceInstance(ComponentInstance resourceInstance, String resourceInvariantUUID, String resourceType, List<ArtifactInfoImpl> artifacts) { + super(); + this.resourceInstanceName = resourceInstance.getName(); + this.resourceName = resourceInstance.getComponentName(); + this.resourceVersion = resourceInstance.getComponentVersion(); + this.resoucreType = resourceType; + this.resourceUUID = resourceInstance.getComponentUid(); + this.resourceInvariantUUID = resourceInvariantUUID; + this.artifacts = artifacts; + } + + public String getResourceInstanceName() { + return resourceInstanceName; + } + + public void setResourceInstanceName(String resourceInstanceName) { + this.resourceInstanceName = resourceInstanceName; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + public String getResoucreType() { + return resoucreType; + } + + public void setResoucreType(String resoucreType) { + this.resoucreType = resoucreType; + } + + public String getResourceUUID() { + return resourceUUID; + } + + public void setResourceUUID(String resourceUUID) { + this.resourceUUID = resourceUUID; + } + + public List<ArtifactInfoImpl> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<ArtifactInfoImpl> artifacts) { + this.artifacts = artifacts; + } + + public String getResourceInvariantUUID() { + return resourceInvariantUUID; + } + + public void setResourceInvariantUUID(String resourceInvariantUUID) { + this.resourceInvariantUUID = resourceInvariantUUID; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java new file mode 100644 index 0000000000..8a2ef8e63b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java @@ -0,0 +1,118 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.List; + +public class NotificationDataImpl implements INotificationData { + + private String distributionID; + private String serviceName; + private String serviceVersion; + private String serviceUUID; + private String serviceDescription; + private String serviceInvariantUUID; + private List<JsonContainerResourceInstance> resources; + private List<ArtifactInfoImpl> serviceArtifacts; + + @Override + public String getDistributionID() { + return distributionID; + } + + @Override + public String getServiceName() { + return serviceName; + } + + @Override + public String getServiceVersion() { + return serviceVersion; + } + + @Override + public String getServiceUUID() { + return serviceUUID; + } + + public void setDistributionID(String distributionID) { + this.distributionID = distributionID; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public void setServiceVersion(String serviceVersion) { + this.serviceVersion = serviceVersion; + } + + public void setServiceUUID(String serviceUUID) { + this.serviceUUID = serviceUUID; + } + + public String getServiceDescription() { + return serviceDescription; + } + + public void setServiceDescription(String serviceDescription) { + this.serviceDescription = serviceDescription; + } + + @Override + public String toString() { + return "NotificationDataImpl [distributionID=" + distributionID + ", serviceName=" + serviceName + ", serviceVersion=" + serviceVersion + ", serviceUUID=" + serviceUUID + ", serviceInvariantUUID=" + serviceInvariantUUID + "]"; + } + + @Override + public List<JsonContainerResourceInstance> getResources() { + return resources; + } + + @Override + public void setResources(List<JsonContainerResourceInstance> resources) { + this.resources = resources; + + } + + @Override + public List<ArtifactInfoImpl> getServiceArtifacts() { + // TODO Auto-generated method stub + return serviceArtifacts; + } + + @Override + public void setServiceArtifacts(List<ArtifactInfoImpl> serviceArtifacts) { + this.serviceArtifacts = serviceArtifacts; + + } + + @Override + public String getServiceInvariantUUID() { + return serviceInvariantUUID; + } + + @Override + public void setServiceInvariantUUID(String serviceInvariantUUID) { + this.serviceInvariantUUID = serviceInvariantUUID; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationExecutorService.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationExecutorService.java new file mode 100644 index 0000000000..74fbb2c660 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationExecutorService.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.openecomp.sdc.be.config.DistributionEngineConfiguration.DistributionNotificationTopicConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +public class NotificationExecutorService { + + private static Logger logger = LoggerFactory.getLogger(NotificationExecutorService.class.getName()); + + public ExecutorService createExcecutorService(DistributionNotificationTopicConfig distributionNotificationTopic) { + + Integer minThreadPoolSize = distributionNotificationTopic.getMinThreadPoolSize(); + if (minThreadPoolSize == null) { + minThreadPoolSize = 0; + } + + Integer maxThreadPoolSize = distributionNotificationTopic.getMaxThreadPoolSize(); + if (maxThreadPoolSize == null) { + maxThreadPoolSize = 10; + } + + ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder(); + threadFactoryBuilder.setNameFormat("distribution-notification-thread-%d"); + ThreadFactory threadFactory = threadFactoryBuilder.build(); + + ExecutorService executorService = new ThreadPoolExecutor(minThreadPoolSize, maxThreadPoolSize, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); + + return executorService; + } + + public void shutdownAndAwaitTermination(ExecutorService pool, long maxTimeToWait) { + + logger.debug("shutdown NotificationExecutorService"); + pool.shutdown(); // Disable new tasks from being submitted + try { + // Wait a while for existing tasks to terminate + if (!pool.awaitTermination(maxTimeToWait, TimeUnit.SECONDS)) { + pool.shutdownNow(); // Cancel currently executing tasks + // Wait a while for tasks to respond to being cancelled + if (!pool.awaitTermination(maxTimeToWait, TimeUnit.SECONDS)) { + logger.debug("Failed to close executor service"); + } + } + } catch (InterruptedException ie) { + // (Re-)Cancel if current thread also interrupted + pool.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/PublishNotificationRunnable.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/PublishNotificationRunnable.java new file mode 100644 index 0000000000..362f3948ed --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/PublishNotificationRunnable.java @@ -0,0 +1,156 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.be.distribution.api.client.CambriaOperationStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.util.ThreadLocalsHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PublishNotificationRunnable implements Runnable { + + private String envName; + private String distributionId; + private Service service; + private INotificationData data; + private DistributionEngineConfiguration deConfiguration; + private String topicName; + private CambriaHandler cambriaHandler; + private ComponentsUtils componentUtils; + private String userId; + private String modifierName; + private String requestId; + + private static Logger logger = LoggerFactory.getLogger(PublishNotificationRunnable.class.getName()); + + public PublishNotificationRunnable(String envName, String distributionId, Service service, INotificationData data, DistributionEngineConfiguration deConfiguration, String topicName, String userId, String modifierName, + CambriaHandler cambriaHandler, ComponentsUtils componentUtils, String requestId) { + super(); + this.envName = envName; + this.distributionId = distributionId; + this.service = service; + this.data = data; + this.deConfiguration = deConfiguration; + this.topicName = topicName; + this.cambriaHandler = cambriaHandler; + this.componentUtils = componentUtils; + this.userId = userId; + this.modifierName = modifierName; + this.requestId = requestId; + } + + public INotificationData getData() { + return data; + } + + public void setData(INotificationData data) { + this.data = data; + } + + public DistributionEngineConfiguration getDeConfiguration() { + return deConfiguration; + } + + public void setDeConfiguration(DistributionEngineConfiguration deConfiguration) { + this.deConfiguration = deConfiguration; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getModifierName() { + return modifierName; + } + + public void setModifierName(String modifierName) { + this.modifierName = modifierName; + } + + @Override + public void run() { + + long startTime = System.currentTimeMillis(); + ThreadLocalsHolder.setUuid(this.requestId); + + CambriaErrorResponse status = cambriaHandler.sendNotificationAndClose(topicName, deConfiguration.getUebPublicKey(), deConfiguration.getUebSecretKey(), deConfiguration.getUebServers(), data, + deConfiguration.getDistributionNotificationTopic().getMaxWaitingAfterSendingSeconds().longValue()); + + logger.info("After publishing service {} of version {}. Status is {}", service.getName(), service.getVersion(), status.getHttpCode()); + auditDistributionNotification(topicName, status, service, distributionId, envName, userId, modifierName); + + long endTime = System.currentTimeMillis(); + logger.debug("After building and publishing artifacts object. Total took {} milliseconds.", (endTime - startTime)); + + } + + private void auditDistributionNotification(String topicName, CambriaErrorResponse status, Service service, String distributionId, String envName, String userId, String modifierName) { + if (this.componentUtils != null) { + Integer httpCode = status.getHttpCode(); + String httpCodeStr = String.valueOf(httpCode); + + String desc = getDescriptionFromErrorResponse(status); + + this.componentUtils.auditDistributionNotification(AuditingActionEnum.DISTRIBUTION_NOTIFY, service.getUUID(), service.getName(), "Service", service.getVersion(), userId, modifierName, envName, service.getLifecycleState().name(), topicName, + distributionId, desc, httpCodeStr); + } + } + + private String getDescriptionFromErrorResponse(CambriaErrorResponse status) { + + CambriaOperationStatus operationStatus = status.getOperationStatus(); + + switch (operationStatus) { + case OK: + return "OK"; + case AUTHENTICATION_ERROR: + return "Error: Authentication problem towards U-EB server"; + case INTERNAL_SERVER_ERROR: + return "Error: Internal U-EB server error"; + case UNKNOWN_HOST_ERROR: + return "Error: Cannot reach U-EB server host"; + case CONNNECTION_ERROR: + return "Error: Cannot connect to U-EB server"; + case OBJECT_NOT_FOUND: + return "Error: object not found in U-EB server"; + default: + return "Error: Internal Cambria server problem"; + + } + + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ResourceArtifactInfoImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ResourceArtifactInfoImpl.java new file mode 100644 index 0000000000..31f3cb6fda --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ResourceArtifactInfoImpl.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public class ResourceArtifactInfoImpl extends ArtifactInfoImpl implements IResourceArtifactInfo { + + private String resourceName; + private String resourceVersion; + private String resourceUUID; + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + public String getResourceUUID() { + return resourceUUID; + } + + public void setResourceUUID(String resourceUUID) { + this.resourceUUID = resourceUUID; + } + + @Override + public String toString() { + return "ResourceArtifactInfoImpl [resourceName=" + resourceName + ", resourceVersion=" + resourceVersion + ", resourceUUID=" + resourceUUID + super.toString() + "]"; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ServiceArtifactInfoImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ServiceArtifactInfoImpl.java new file mode 100644 index 0000000000..50d1700f37 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ServiceArtifactInfoImpl.java @@ -0,0 +1,30 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public class ServiceArtifactInfoImpl extends ArtifactInfoImpl implements IServiceArtifactInfo { + + @Override + public String toString() { + return "ServiceArtifactInfoImpl [" + super.toString() + "]"; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ServiceDistributionArtifactsBuilder.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ServiceDistributionArtifactsBuilder.java new file mode 100644 index 0000000000..da148ee80a --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/ServiceDistributionArtifactsBuilder.java @@ -0,0 +1,268 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.operations.api.IArtifactOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.ServiceOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("serviceDistributionArtifactsBuilder") +public class ServiceDistributionArtifactsBuilder { + + private int defaultArtifactInstallTimeout = 60; + + private static Logger logger = LoggerFactory.getLogger(ServiceDistributionArtifactsBuilder.class.getName()); + + final static String BASE_ARTIFACT_URL = "/asdc/v1/catalog/services/%s/%s/"; + final static String RESOURCE_ARTIFACT_URL = BASE_ARTIFACT_URL + "resources/%s/%s/artifacts/%s"; + final static String SERVICE_ARTIFACT_URL = BASE_ARTIFACT_URL + "artifacts/%s"; + + final static String RESOURCE_INSTANCE_ARTIFACT_URL = BASE_ARTIFACT_URL + "resourceInstances/%s/artifacts/%s"; + + @javax.annotation.Resource + ServiceOperation serviceOperation; + + @javax.annotation.Resource + ResourceOperation resourceOperation; + + @javax.annotation.Resource + InterfaceLifecycleOperation interfaceLifecycleOperation; + + @javax.annotation.Resource + IArtifactOperation artifactOperation; + + /* + * @javax.annotation.Resource private InformationDeployedArtifactsBusinessLogic informationDeployedArtifactsBusinessLogic; + */ + + @PostConstruct + private void init() { + defaultArtifactInstallTimeout = ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultHeatArtifactTimeoutMinutes(); + } + + public ServiceOperation getServiceOperation() { + return serviceOperation; + } + + public void setServiceOperation(ServiceOperation serviceOperation) { + this.serviceOperation = serviceOperation; + } + + public ResourceOperation getResourceOperation() { + return resourceOperation; + } + + public void setResourceOperation(ResourceOperation resourceOperation) { + this.resourceOperation = resourceOperation; + } + + public InterfaceLifecycleOperation getInterfaceLifecycleOperation() { + return interfaceLifecycleOperation; + } + + public void setInterfaceLifecycleOperation(InterfaceLifecycleOperation interfaceLifecycleOperation) { + this.interfaceLifecycleOperation = interfaceLifecycleOperation; + } + + public INotificationData buildResourceInstanceForDistribution(Service service, String distributionId) { + INotificationData notificationData = new NotificationDataImpl(); + + notificationData.setResources(convertRIToJsonContanier(service)); + notificationData.setServiceName(service.getName()); + notificationData.setServiceVersion(service.getVersion()); + notificationData.setDistributionID(distributionId); + notificationData.setServiceUUID(service.getUUID()); + notificationData.setServiceDescription(service.getDescription()); + notificationData.setServiceInvariantUUID(service.getInvariantUUID()); + + logger.debug("Before returning notification data object {}", notificationData); + + return notificationData; + + } + + public INotificationData buildServiceForDistribution(INotificationData notificationData, Service service) { + + notificationData.setServiceArtifacts(convertServiceArtifactsToArtifactInfo(service)); + + logger.debug("Before returning notification data object {}", notificationData); + + return notificationData; + + } + + private List<ArtifactInfoImpl> convertServiceArtifactsToArtifactInfo(Service service) { + + Map<String, ArtifactDefinition> serviceArtifactsMap = service.getDeploymentArtifacts(); + List<ArtifactDefinition> ret = new ArrayList<ArtifactDefinition>(); + + for (ArtifactDefinition artifactDef : serviceArtifactsMap.values()) { + if (artifactDef.checkEsIdExist()) { + ret.add(artifactDef); + } + } + List<ArtifactInfoImpl> artifacts = ArtifactInfoImpl.convertServiceArtifactToArtifactInfoImpl(service, ret); + return artifacts; + } + + private List<JsonContainerResourceInstance> convertRIToJsonContanier(Service service) { + List<JsonContainerResourceInstance> ret = new ArrayList<JsonContainerResourceInstance>(); + if (service.getComponentInstances() != null) { + for (ComponentInstance resourceInstance : service.getComponentInstances()) { + String resoucreType = "VF"; + List<ArtifactDefinition> artifactsDefList = getArtifactsWithPayload(resourceInstance); + List<ArtifactInfoImpl> artifacts = ArtifactInfoImpl.convertToArtifactInfoImpl(service, resourceInstance, artifactsDefList); + Either<String, StorageOperationStatus> responseResult = resourceOperation.getInvariantUUID(NodeTypeEnum.Resource, resourceInstance.getComponentUid(), false); + String resourceInvariantUUID = null; + if (responseResult.isRight()) { + logger.debug("Resource {} Invariant UUID retrieving failed", resourceInstance.getComponentUid()); + } else { + resourceInvariantUUID = responseResult.left().value(); + } + JsonContainerResourceInstance jsonContainer = new JsonContainerResourceInstance(resourceInstance, resourceInvariantUUID, resoucreType, artifacts); + ret.add(jsonContainer); + } + + } + return ret; + } + + private List<ArtifactDefinition> getArtifactsWithPayload(ComponentInstance resourceInstance) { + List<ArtifactDefinition> ret = new ArrayList<ArtifactDefinition>(); + + // List<ArtifactDefinition> informationDeployedArtifacts = + // informationDeployedArtifactsBusinessLogic.getInformationalDeployedArtifactsForResourceInstance(resourceInstance); + List<ArtifactDefinition> deployableArtifacts = new ArrayList<ArtifactDefinition>(); + // deployableArtifacts.addAll(informationDeployedArtifacts); + if (resourceInstance.getDeploymentArtifacts() != null) { + deployableArtifacts.addAll(resourceInstance.getDeploymentArtifacts().values()); + } + + for (ArtifactDefinition artifactDef : deployableArtifacts) { + if (artifactDef.checkEsIdExist()) { + ret.add(artifactDef); + } + } + + return ret; + } + + /** + * build the url for resource intance artifact + * + * @param service + * @param resourceData + * @param artifactName + * @return + */ + public static String buildResourceInstanceArtifactUrl(Service service, ComponentInstance resourceInstance, String artifactName) { + + String url = String.format(RESOURCE_INSTANCE_ARTIFACT_URL, service.getSystemName(), service.getVersion(), resourceInstance.getNormalizedName(), artifactName); + + logger.debug("After building artifact url {}", url); + + return url; + } + + /** + * build the url for resource intance artifact + * + * @param service + * @param resourceData + * @param artifactName + * @return + */ + public static String buildServiceArtifactUrl(Service service, String artifactName) { + + String url = String.format(SERVICE_ARTIFACT_URL, service.getSystemName(), service.getVersion(), artifactName); + + logger.debug("After building artifact url {}", url); + + return url; + + } + + /** + * Retrieve all deployment artifacts of all resources under a given service + * + * @param resourceArtifactsResult + * @param service + * @param deConfiguration + * @return + */ + public Either<Boolean, StorageOperationStatus> isServiceContainsDeploymentArtifacts(Service service) { + + Either<Boolean, StorageOperationStatus> result = Either.left(false); + Map<String, ArtifactDefinition> serviseArtifactsMap = service.getDeploymentArtifacts(); + if (serviseArtifactsMap != null && !serviseArtifactsMap.isEmpty()) { + result = Either.left(true); + return result; + } + + List<ComponentInstance> resourceInstances = service.getComponentInstances(); + + if (resourceInstances != null) { + for (ComponentInstance resourceInstance : resourceInstances) { + + Map<String, ArtifactDefinition> deploymentArtifactsMapper = resourceInstance.getDeploymentArtifacts(); + // List<ArtifactDefinition> informationDeployedArtifacts = + // informationDeployedArtifactsBusinessLogic.getInformationalDeployedArtifactsForResourceInstance(resourceInstance); + + boolean isDeployableArtifactFound = isContainsPayload(deploymentArtifactsMapper.values());// || + // isContainsPayload(informationDeployedArtifacts); + if (isDeployableArtifactFound) { + result = Either.left(true); + break; + } + + } + + } + + return result; + } + + private boolean isContainsPayload(Collection<ArtifactDefinition> collection) { + boolean payLoadFound = collection != null && collection.stream().anyMatch(p -> p.checkEsIdExist()); + return payLoadFound; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/SubscriberTypeEnum.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/SubscriberTypeEnum.java new file mode 100644 index 0000000000..f8c0e3f593 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/SubscriberTypeEnum.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +public enum SubscriberTypeEnum { + + CONSUMER, PRODUCER; +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/TestQueue.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/TestQueue.java new file mode 100644 index 0000000000..c9e3c4e34d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/TestQueue.java @@ -0,0 +1,188 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +public class TestQueue { + + public static void main(String[] args) { + ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder(); + threadFactoryBuilder.setNameFormat("distribution-notification-thread"); + ThreadFactory threadFactory = threadFactoryBuilder.build(); + // TODO: add the package of google to the pom + + ExecutorService executorService = new ThreadPoolExecutor(0, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); + // ExecutorService executorService = new ThreadPoolExecutor(0, 2, 60L, + // TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20)); + + // 2 threads are always up and they handle the tasks. in case core size + // is 0, only one is handles the tasks. + // ExecutorService executorService = new ThreadPoolExecutor(0, 2, 60L, + // TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20)); + + // TODO : check what happen when the number of threads are full. Throw + // RejectedExecutionException + // TODO : check what happen whether the pool is full and the size of + // pool + + ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(threadFactory); + Runnable task = new Runnable() { + + @Override + public void run() { + // TODO Auto-generated method stub + try { + System.out.println("iN SLEEP" + Thread.currentThread()); + Thread.sleep(10 * 1000); + System.out.println("OUT SLEEP"); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }; + + for (int i = 0; i < 4; i++) { + try { + executorService.submit(task); + } catch (RejectedExecutionException e) { + e.printStackTrace(); + } + } + + newCachedThreadPool.submit(task); + System.out.println("After submitting the task"); + + MyWorker[] watchThreads = new MyWorker[1]; + BlockingQueue<String> queue = new ArrayBlockingQueue<>(5); + for (int i = 0; i < watchThreads.length; i++) { + MyWorker myWorker = new MyWorker(queue); + myWorker.start(); + } + + for (int i = 0; i < 1; i++) { + try { + queue.put("message " + i); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } + + public static class MyTimerTask extends TimerTask { + + AtomicBoolean state; + Thread thread; + + public MyTimerTask(AtomicBoolean state, Thread thread) { + super(); + this.state = state; + this.thread = thread; + + System.out.println("After create timer"); + } + + @Override + public void run() { + System.out.println("In running of Timer task"); + if (state.get() == false) { + System.out.println("In running of Timer task. Going to interrupt thread"); + // thread.interrupt(); + } else { + System.out.println("In running of Timer task. Finished."); + } + } + + } + + public static class MyWorker extends Thread { + + boolean active = true; + private final BlockingQueue<String> queue; + + public MyWorker(BlockingQueue<String> queue) { + this.queue = queue; + } + + Timer timer = new Timer(); + + public void run() { + try { + while (active) { + String s = queue.take(); + System.out.println("Thread " + Thread.currentThread() + " fecthed a message " + s); + + AtomicBoolean atomicBoolean = new AtomicBoolean(false); + MyTimerTask myTimerTask = new MyTimerTask(atomicBoolean, this); + timer.schedule(myTimerTask, 10 * 1000); + doWork(s); + atomicBoolean.set(true); + + } + } catch (InterruptedException ie) { + + System.out.println("Interrupted our thread"); + ie.printStackTrace(); + } + } + + private void doWork(String s) { + // TODO Auto-generated method stub + + CambriaHandler cambriaHandler = new CambriaHandler(); + INotificationData data = new NotificationDataImpl(); + List<String> servers = new ArrayList<>(); + servers.add("aaaaaaa"); + cambriaHandler.sendNotification("topicName", "uebPublicKey", "uebSecretKey", servers, data); + + System.out.println("IN WORK " + s); + try { + Thread.sleep(1 * 1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + + for (int i = 0; i < 10; i++) { + System.out.println("*************************************************"); + } + e.printStackTrace(); + } + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/UebHealthCheckCall.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/UebHealthCheckCall.java new file mode 100644 index 0000000000..c522ca91b5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/UebHealthCheckCall.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.concurrent.Callable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UebHealthCheckCall implements Callable<Boolean> { + + CambriaHandler cambriaHandler = new CambriaHandler(); + + String server; + String publicApiKey; + + private static Logger healthLogger = LoggerFactory.getLogger(DistributionEngineClusterHealth.UEB_HEALTH_LOG_CONTEXT); + + private static Logger logger = LoggerFactory.getLogger(UebHealthCheckCall.class.getName()); + + public UebHealthCheckCall(String server, String publicApiKey) { + super(); + this.server = server; + this.publicApiKey = publicApiKey; + } + + @Override + public Boolean call() { + + healthLogger.trace("Going to run health check towards ueb server {}", server); + + boolean result = false; + CambriaErrorResponse cambriaErrorResponse = cambriaHandler.getApiKey(server, publicApiKey); + + logger.debug("After running Health check towards ueb server {}. Result is {}", server, cambriaErrorResponse); + + if (cambriaErrorResponse.httpCode < CambriaErrorResponse.HTTP_INTERNAL_SERVER_ERROR) { + logger.debug("After running Health check towards ueb server {}. Error code is {}. Set result to true", server, cambriaErrorResponse.httpCode); + result = true; + } + + healthLogger.trace("Result after running health check towards ueb server {} is {}. Returned result is {} ", server, cambriaErrorResponse, result); + + return result; + } + + public String getServer() { + return server; + } + + public CambriaHandler getCambriaHandler() { + return cambriaHandler; + } + + public void setCambriaHandler(CambriaHandler cambriaHandler) { + this.cambriaHandler = cambriaHandler; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java new file mode 100644 index 0000000000..89cb6d91ee --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.distribution.engine; + +import java.util.List; +import java.util.Optional; + +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.GroupProperty; +import org.openecomp.sdc.common.api.Constants; + +public class VfModuleArtifactPayload { + public VfModuleArtifactPayload(GroupDefinition group) { + vfModuleModelName = group.getName(); + vfModuleModelInvariantUUID = group.getInvariantUUID(); + vfModuleModelVersion = group.getVersion(); + vfModuleModelUUID = group.getGroupUUID(); + vfModuleModelDescription = group.getDescription(); + + artifacts = group.getArtifactsUuid(); + // Base Value is set from properties + setBaseValue(group); + + } + + private void setBaseValue(GroupDefinition group) { + if (group.getProperties() != null) { + Optional<GroupProperty> findBaseProperty = group.getProperties().stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny(); + if (findBaseProperty.isPresent()) { + isBase = Boolean.valueOf(findBaseProperty.get().getValue()); + } + + } + } + + private String vfModuleModelName, vfModuleModelInvariantUUID, vfModuleModelVersion, vfModuleModelUUID, vfModuleModelDescription; + private Boolean isBase; + private List<String> artifacts; + + public List<String> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<String> artifacts) { + this.artifacts = artifacts; + } + + public static int compareByGroupName(VfModuleArtifactPayload art1, VfModuleArtifactPayload art2) { + Integer thisCounter = Integer.parseInt(art1.vfModuleModelName.split(Constants.MODULE_NAME_DELIMITER)[1]); + Integer otherCounter = Integer.parseInt(art2.vfModuleModelName.split(Constants.MODULE_NAME_DELIMITER)[1]); + return thisCounter.compareTo(otherCounter); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AdditionalInformationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AdditionalInformationBusinessLogic.java new file mode 100644 index 0000000000..e01d4c238c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AdditionalInformationBusinessLogic.java @@ -0,0 +1,573 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.List; + +import javax.servlet.ServletContext; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.graph.datatype.AdditionalInformationEnum; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.AdditionalInfoParameterInfo; +import org.openecomp.sdc.be.model.AdditionalInformationDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.IAdditionalInformationOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.IServiceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.model.tosca.converters.StringConvertor; +import org.openecomp.sdc.be.model.tosca.validators.StringValidator; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.WebApplicationContext; + +import fj.data.Either; + +@Component("additionalInformationBusinessLogic") +public class AdditionalInformationBusinessLogic extends BaseBusinessLogic { + + private static final String CREATE_ADDITIONAL_INFORMATION = "CreateAdditionalInformation"; + + private static final String UPDATE_ADDITIONAL_INFORMATION = "UpdateAdditionalInformation"; + + private static final String DELETE_ADDITIONAL_INFORMATION = "DeleteAdditionalInformation"; + + private static final String GET_ADDITIONAL_INFORMATION = "GetAdditionalInformation"; + + private static Logger log = LoggerFactory.getLogger(AdditionalInformationBusinessLogic.class.getName()); + + @javax.annotation.Resource + private IAdditionalInformationOperation additionalInformationOperation = null; + + @javax.annotation.Resource + private IResourceOperation resourceOperation; + + @javax.annotation.Resource + private IServiceOperation serviceOperation; + + @javax.annotation.Resource + private IGraphLockOperation graphLockOperation; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + protected static IElementOperation getElementDao(Class<IElementOperation> class1, ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + + return webApplicationContext.getBean(class1); + } + + /** + * Create new additional information on resource/service on graph + * + * @param resourceId + * @param propertyName + * @param newPropertyDefinition + * @param userId + * @return Either<PropertyDefinition, ActionStatus> + */ + public Either<AdditionalInfoParameterInfo, ResponseFormat> createAdditionalInformation(NodeTypeEnum nodeType, String resourceId, AdditionalInfoParameterInfo additionalInfoParameterInfo, String additionalInformationUid, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Additional Information", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<AdditionalInfoParameterInfo, ResponseFormat> result = null; + + ResponseFormat responseFormat = verifyCanWorkOnComponent(nodeType, resourceId, userId); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + + // lock component + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, nodeType); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedLockObjectError, CREATE_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_ADDITIONAL_INFORMATION, nodeType.getName(), resourceId); + log.info("Failed to lock component {} error - {}", resourceId, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + try { + responseFormat = validateMaxSizeNotReached(nodeType, resourceId, additionalInfoParameterInfo); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + + // validate label + responseFormat = validateAndConvertKey(additionalInfoParameterInfo, CREATE_ADDITIONAL_INFORMATION); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + + // validate value + responseFormat = validateAndConvertValue(additionalInfoParameterInfo, CREATE_ADDITIONAL_INFORMATION); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + + Either<AdditionalInformationDefinition, StorageOperationStatus> addResult = additionalInformationOperation.createAdditionalInformationParameter(nodeType, resourceId, additionalInfoParameterInfo.getKey(), + additionalInfoParameterInfo.getValue(), true); + + if (addResult.isRight()) { + StorageOperationStatus status = addResult.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, CREATE_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeSystemError(CREATE_ADDITIONAL_INFORMATION); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = Either.right(componentsUtils.getResponseFormatAdditionalProperty(actionStatus, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.Label)); + return result; + + } else { + AdditionalInformationDefinition informationDefinition = addResult.left().value(); + + AdditionalInfoParameterInfo createdAI = findAdditionInformationKey(informationDefinition.getParameters(), additionalInfoParameterInfo.getKey()); + result = Either.left(createdAI); + return result; + } + + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, nodeType); + } + + } + + /** + * Validate the value format. Format the value. + * + * @param additionalInfoParameterInfo + * @return null in case of success. Otherwise response format. + */ + private ResponseFormat validateAndConvertValue(AdditionalInfoParameterInfo additionalInfoParameterInfo, String context) { + ResponseFormat result = null; + + String value = additionalInfoParameterInfo.getValue(); + log.debug("Going to validate additional information value {}", value); + + Either<String, ResponseFormat> valueValidRes = validateValue(value); + if (valueValidRes.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidValueError, context, additionalInfoParameterInfo.getValue(), "additional information value", "string"); + BeEcompErrorManager.getInstance().logBeInvalidValueError(context, additionalInfoParameterInfo.getValue(), "additional information value", "string"); + result = valueValidRes.right().value(); + } else { + String newValue = valueValidRes.left().value(); + if (log.isTraceEnabled()) { + if (value != null && false == value.equals(newValue)) { + log.trace("The additional information value was normalized from {} to {}", value, newValue); + } + } + additionalInfoParameterInfo.setValue(newValue); + } + return result; + } + + /** + * @param additionalInfoParameterInfo + * @return + */ + private ResponseFormat validateAndConvertKey(AdditionalInfoParameterInfo additionalInfoParameterInfo, String context) { + + String key = additionalInfoParameterInfo.getKey(); + log.debug("Going to validate additional information key {}", key); + + ResponseFormat result = null; + ResponseFormat responseFormat; + Either<String, ResponseFormat> validateKeyRes = validateAndNormalizeKey(key); + if (validateKeyRes.isRight()) { + responseFormat = validateKeyRes.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidValueError, context, additionalInfoParameterInfo.getKey(), "additional information label", "string"); + BeEcompErrorManager.getInstance().logBeInvalidValueError(context, additionalInfoParameterInfo.getKey(), "additional information label", "string"); + result = responseFormat; + + } else { + String convertedKey = validateKeyRes.left().value(); + + if (log.isTraceEnabled()) { + if (key != null && false == key.equals(convertedKey)) { + log.trace("The additional information key {} was normalized to {}", key, convertedKey); + } + } + additionalInfoParameterInfo.setKey(convertedKey); + } + return result; + } + + /** + * verify that the maximal number of additional information properties has not been reached. + * + * @param nodeType + * @param componentId + * @param additionalInfoParameterInfo + * @return response format in case the maximal number has been reached. + */ + private ResponseFormat validateMaxSizeNotReached(NodeTypeEnum nodeType, String componentId, AdditionalInfoParameterInfo additionalInfoParameterInfo) { + + ResponseFormat result; + Integer additionalInformationMaxNumberOfKeys = ConfigurationManager.getConfigurationManager().getConfiguration().getAdditionalInformationMaxNumberOfKeys(); + + Either<Integer, StorageOperationStatus> checkRes = additionalInformationOperation.getNumberOfAdditionalInformationParameters(nodeType, componentId, true); + if (checkRes.isRight()) { + StorageOperationStatus status = checkRes.right().value(); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = componentsUtils.getResponseFormatAdditionalProperty(actionStatus, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.None); + return result; + } + Integer currentNumberOfProperties = checkRes.left().value(); + if (currentNumberOfProperties >= additionalInformationMaxNumberOfKeys) { + log.info("The current number of additional information properties is {}. The maximum allowed additional information properties is {}", currentNumberOfProperties, currentNumberOfProperties); + result = componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.ADDITIONAL_INFORMATION_MAX_NUMBER_REACHED, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.None); + return result; + } + + return null; + } + + /** + * validate additional information value + * + * @param value + * @return + */ + private Either<String, ResponseFormat> validateValue(String value) { + + boolean isNonEmptyString = ValidationUtils.validateStringNotEmpty(value); + if (false == isNonEmptyString) { + return Either.right(componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.ADDITIONAL_INFORMATION_EMPTY_STRING_NOT_ALLOWED)); + } + + boolean valid = StringValidator.getInstance().isValid(value, null); + if (false == valid) { + return Either.right(componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.ADDITIONAL_INFORMATION_VALUE_NOT_ALLOWED_CHARACTERS, new AdditionalInfoParameterInfo(null, value), null, AdditionalInformationEnum.Value)); + } + + String converted = StringConvertor.getInstance().convert(value, null, null); + + return Either.left(converted); + } + + private AdditionalInfoParameterInfo findAdditionInformationKey(List<AdditionalInfoParameterInfo> parameters, String key) { + + for (AdditionalInfoParameterInfo infoParameterInfo : parameters) { + if (infoParameterInfo.getKey().equals(key)) { + return infoParameterInfo; + } + } + return null; + } + + /** + * validate and normalize the key + * + * @param additionalInfoParameterInfo + * @return + */ + private Either<String, ResponseFormat> validateAndNormalizeKey(String key) { + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(); + additionalInfoParameterInfo.setKey(key); + + key = ValidationUtils.normalizeAdditionalInformation(key); + boolean isNonEmptyString = ValidationUtils.validateStringNotEmpty(key); + if (false == isNonEmptyString) { + return Either.right(componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.ADDITIONAL_INFORMATION_EMPTY_STRING_NOT_ALLOWED, null, null, AdditionalInformationEnum.Label)); + } + boolean isValidString = ValidationUtils.validateAdditionalInformationKeyName(key); + if (false == isValidString) { + if (false == ValidationUtils.validateLength(key, ValidationUtils.ADDITIONAL_INFORMATION_KEY_MAX_LENGTH)) { + return Either.right(componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.ADDITIONAL_INFORMATION_EXCEEDS_LIMIT, additionalInfoParameterInfo, null, AdditionalInformationEnum.Label)); + } + return Either.right(componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.ADDITIONAL_INFORMATION_KEY_NOT_ALLOWED_CHARACTERS, additionalInfoParameterInfo, null, AdditionalInformationEnum.Label)); + } + + return Either.left(key); + } + + /** + * update key and value of a given additional information. + * + * @param nodeType + * @param resourceId + * @param additionalInfoParameterInfo + * @param additionalInformationUid + * - Future use + * @param userId + * @return + */ + public Either<AdditionalInfoParameterInfo, ResponseFormat> updateAdditionalInformation(NodeTypeEnum nodeType, String resourceId, AdditionalInfoParameterInfo additionalInfoParameterInfo, String additionalInformationUid, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Additional Information", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<AdditionalInfoParameterInfo, ResponseFormat> result = null; + + ResponseFormat responseFormat = verifyCanWorkOnComponent(nodeType, resourceId, userId); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + // lock component + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, nodeType); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedLockObjectError, UPDATE_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(UPDATE_ADDITIONAL_INFORMATION, nodeType.getName(), resourceId); + log.info("Failed to lock component {} error - {}", resourceId, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + try { + + // validate input + responseFormat = validateAndConvertKey(additionalInfoParameterInfo, UPDATE_ADDITIONAL_INFORMATION); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + + responseFormat = validateAndConvertValue(additionalInfoParameterInfo, UPDATE_ADDITIONAL_INFORMATION); + if (responseFormat != null) { + result = Either.right(responseFormat); + return result; + } + + Either<AdditionalInformationDefinition, StorageOperationStatus> addResult = additionalInformationOperation.updateAdditionalInformationParameter(nodeType, resourceId, additionalInfoParameterInfo.getUniqueId(), + additionalInfoParameterInfo.getKey(), additionalInfoParameterInfo.getValue(), true); + + if (addResult.isRight()) { + StorageOperationStatus status = addResult.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, UPDATE_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeSystemError(UPDATE_ADDITIONAL_INFORMATION); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = Either.right(componentsUtils.getResponseFormatAdditionalProperty(actionStatus, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.None)); + return result; + } else { + AdditionalInformationDefinition informationDefinition = addResult.left().value(); + AdditionalInfoParameterInfo parameterInfo = findAdditionInformationKey(informationDefinition.getParameters(), additionalInfoParameterInfo.getKey()); + result = Either.left(parameterInfo); + return result; + } + + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, nodeType); + } + + } + + /** + * Delete an additional information label + * + * @param nodeType + * @param resourceId + * @param additionalInfoParameterInfo + * @param additionalInformationUid + * - Null. Future use. + * @param userId + * @return + */ + public Either<AdditionalInfoParameterInfo, ResponseFormat> deleteAdditionalInformation(NodeTypeEnum nodeType, String resourceId, AdditionalInfoParameterInfo additionalInfoParameterInfo, String additionalInformationUid, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Additional Information", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<AdditionalInfoParameterInfo, ResponseFormat> result = null; + + ResponseFormat responseFormat = verifyCanWorkOnComponent(nodeType, resourceId, userId); + if (responseFormat != null) { + return Either.right(responseFormat); + } + // lock component + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, nodeType); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedLockObjectError, DELETE_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(DELETE_ADDITIONAL_INFORMATION, nodeType.getName(), resourceId); + log.info("Failed to lock component {} error - {}", resourceId, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + + Either<AdditionalInfoParameterInfo, StorageOperationStatus> findIdRes = additionalInformationOperation.getAdditionalInformationParameter(nodeType, resourceId, additionalInfoParameterInfo.getUniqueId(), true); + if (findIdRes.isRight()) { + StorageOperationStatus status = findIdRes.right().value(); + if (status != StorageOperationStatus.NOT_FOUND) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, GET_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeSystemError(GET_ADDITIONAL_INFORMATION); + } + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = Either.right(componentsUtils.getResponseFormatAdditionalProperty(actionStatus, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.None)); + return result; + } + + AdditionalInfoParameterInfo foundAdditionalInfo = findIdRes.left().value(); + + Either<AdditionalInformationDefinition, StorageOperationStatus> addResult = additionalInformationOperation.deleteAdditionalInformationParameter(nodeType, resourceId, additionalInfoParameterInfo.getUniqueId(), true); + + if (addResult.isRight()) { + StorageOperationStatus status = addResult.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, DELETE_ADDITIONAL_INFORMATION); + BeEcompErrorManager.getInstance().logBeDaoSystemError(DELETE_ADDITIONAL_INFORMATION); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = Either.right(componentsUtils.getResponseFormatAdditionalProperty(actionStatus, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.None)); + return result; + } else { + result = Either.left(foundAdditionalInfo); + return result; + } + + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, nodeType); + } + + } + + /** + * @param nodeType + * @param resourceId + * @param additionalInfoParameterInfo + * @param additionalInformationUid + * @param userId + * @return + */ + public Either<AdditionalInfoParameterInfo, ResponseFormat> getAdditionalInformation(NodeTypeEnum nodeType, String resourceId, AdditionalInfoParameterInfo additionalInfoParameterInfo, String additionalInformationUid, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Additional Information", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<AdditionalInfoParameterInfo, ResponseFormat> result = null; + + try { + + Either<AdditionalInfoParameterInfo, StorageOperationStatus> findIdRes = additionalInformationOperation.getAdditionalInformationParameter(nodeType, resourceId, additionalInfoParameterInfo.getUniqueId(), true); + + if (findIdRes.isRight()) { + StorageOperationStatus status = findIdRes.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = Either.right(componentsUtils.getResponseFormatAdditionalProperty(actionStatus, additionalInfoParameterInfo, nodeType, AdditionalInformationEnum.None)); + } + + AdditionalInfoParameterInfo foundAdditionalInfo = findIdRes.left().value(); + + result = Either.left(foundAdditionalInfo); + + return result; + + } finally { + commitOrRollback(result); + } + + } + + /** + * Get all additional information properties of a given resource/service + * + * @param nodeType + * @param resourceId + * @param additionalInformationUid + * - Future use + * @param userId + * @return + */ + public Either<AdditionalInformationDefinition, ResponseFormat> getAllAdditionalInformation(NodeTypeEnum nodeType, String resourceId, String additionalInformationUid, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "get All Additional Information", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<AdditionalInformationDefinition, ResponseFormat> result = null; + + try { + + Either<AdditionalInformationDefinition, TitanOperationStatus> findIdRes = additionalInformationOperation.getAllAdditionalInformationParameters(nodeType, resourceId, false); + if (findIdRes.isRight()) { + StorageOperationStatus status = DaoStatusConverter.convertTitanStatusToStorageStatus(findIdRes.right().value()); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForAdditionalInformation(status); + result = Either.right(componentsUtils.getResponseFormatAdditionalProperty(actionStatus)); + } else { + AdditionalInformationDefinition informationDefinition = findIdRes.left().value(); + result = Either.left(informationDefinition); + } + + return result; + + } finally { + commitOrRollback(result); + } + + } + + private ResponseFormat verifyCanWorkOnComponent(NodeTypeEnum nodeType, String resourceId, String userId) { + + switch (nodeType) { + case Resource: + + // verify that resource is checked-out and the user is the last + // updater + if (!ComponentValidationUtils.canWorkOnResource(resourceId, resourceOperation, userId)) { + return componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + } + break; + case Service: + + // verify that resource is checked-out and the user is the last + // updater + if (!ComponentValidationUtils.canWorkOnService(resourceId, serviceOperation, userId)) { + return componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + } + break; + default: + return componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT, nodeType.getName()); + } + + return null; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java new file mode 100644 index 0000000000..16ed4a1868 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java @@ -0,0 +1,4127 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction.LifecycleChanceActionEnum; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.Configuration.DeploymentArtifactTypeConfig; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.validation.DeploymentArtifactHeatConfiguration; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; +import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactType; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.heat.HeatParameterType; +import org.openecomp.sdc.be.model.operations.api.IArtifactOperation; +import org.openecomp.sdc.be.model.operations.api.IComponentInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IHeatParametersOperation; +import org.openecomp.sdc.be.model.operations.api.IInterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.resources.data.ArtifactData; +import org.openecomp.sdc.be.resources.data.ComponentMetadataData; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.resources.data.auditing.AuditingTypesConstants; +import org.openecomp.sdc.be.servlets.RepresentationUtils; +import org.openecomp.sdc.be.tosca.CsarUtils; +import org.openecomp.sdc.be.tosca.ToscaError; +import org.openecomp.sdc.be.tosca.ToscaExportHandler; +import org.openecomp.sdc.be.tosca.ToscaRepresentation; +import org.openecomp.sdc.be.user.IUserBusinessLogic; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.common.util.YamlToObjectConverter; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.yaml.snakeyaml.Yaml; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.sun.org.apache.xerces.internal.parsers.SAXParser; + +import fj.data.Either; + +@org.springframework.stereotype.Component("artifactBusinessLogic") +public class ArtifactsBusinessLogic extends BaseBusinessLogic { + private static final String ARTIFACT_TYPE_OTHER = "OTHER"; + private static final String ARTIFACT_DESCRIPTION = "artifact description"; + private static final String ARTIFACT_LABEL = "artifact label"; + private static final String ARTIFACT_URL = "artifact url"; + private static final String ARTIFACT_NAME = "artifact name"; + private static final String ARTIFACT_PAYLOAD = "artifact payload"; + + private static final String ARTIFACT_PLACEHOLDER_TYPE = "type"; + private static final String ARTIFACT_PLACEHOLDER_DISPLAY_NAME = "displayName"; + private static final Object ARTIFACT_PLACEHOLDER_DESCRIPTION = "description"; + + private static Integer defaultHeatTimeout; + private static final Integer NON_HEAT_TIMEOUT = 0; + private static Logger log = LoggerFactory.getLogger(ArtifactsBusinessLogic.class.getName()); + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @javax.annotation.Resource + private IArtifactOperation artifactOperation; + + // @javax.annotation.Resource + // private IResourceUploader daoUploader; + + @javax.annotation.Resource + private IInterfaceLifecycleOperation interfaceLifecycleOperation; + @javax.annotation.Resource + private IUserAdminOperation userOperaton; + + // @javax.annotation.Resource + // private ESCatalogDAO esCatalogDao; + + @javax.annotation.Resource + private IElementOperation elementOperation; + + @javax.annotation.Resource + private ResourceBusinessLogic resourceBusinessLogic; + + @javax.annotation.Resource + private ServiceBusinessLogic serviceBusinessLogic; + + @javax.annotation.Resource + private UserBusinessLogic userAdminManager; + + @javax.annotation.Resource + private IHeatParametersOperation heatParametersOperation; + + @javax.annotation.Resource + private IComponentInstanceOperation resourceInstanceOperation; + + @Autowired + private ArtifactCassandraDao artifactCassandraDao; + + @Autowired + private ToscaExportHandler toscaExportUtils; + + @Autowired + private CsarUtils csarUtils; + + @Autowired + private LifecycleBusinessLogic lifecycleBusinessLogic; + + @Autowired + private IUserBusinessLogic userBusinessLogic; + + public ArtifactsBusinessLogic() { + defaultHeatTimeout = ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultHeatArtifactTimeoutMinutes(); + if ((defaultHeatTimeout == null) || (defaultHeatTimeout < 1)) { + defaultHeatTimeout = 60; + } + } + + public static enum ArtifactOperation { + + Create(false), Update(false), Delete(false), Download(false); + + private boolean isExternalApi; + + ArtifactOperation(boolean isExternalApi) { + this.isExternalApi = isExternalApi; + } + + public boolean isExternalApi() { + return isExternalApi; + } + + public void setExternalApi(boolean isExternalApi) { + this.isExternalApi = isExternalApi; + } + } + + // new flow US556184 + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleArtifactRequest(String componentId, String userId, ComponentTypeEnum componentType, ArtifactOperation operation, String artifactId, ArtifactDefinition artifactInfo, + String origMd5, String originData, String interfaceName, String operationName, String parentId, String containerComponentType) { + return handleArtifactRequest(componentId, userId, componentType, operation, artifactId, artifactInfo, origMd5, originData, interfaceName, operationName, parentId, containerComponentType, true, false); + } + + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleArtifactRequest(String componentId, String userId, ComponentTypeEnum componentType, ArtifactOperation operation, String artifactId, ArtifactDefinition artifactInfo, + String origMd5, String originData, String interfaceName, String operationName, String parentId, String containerComponentType, boolean shouldLock, boolean inTransaction) { + // step 1 + // detect auditing type + AuditingActionEnum auditingAction = detectAuditingType(operation, origMd5); + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + // step 2 + // check header + if (userId == null) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + log.debug("handleArtifactRequest - no HTTP_CSP_HEADER , component id {}", componentId); + handleAuditing(auditingAction, null, componentId, null, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + // step 3 + // check user existence + // step 4 + // check user's role + Either<User, ResponseFormat> userResult = validateUserExists(userId, auditingAction, componentId, artifactId, componentType, inTransaction); + if (userResult.isRight()) { + return Either.right(userResult.right().value()); + } + + User user = userResult.left().value(); + Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, auditingAction, componentId, artifactId, componentType, operation); + if (validateUserRole.isRight()) { + return Either.right(validateUserRole.right().value()); + } + + // steps 5 - 6 - 7 + // 5. check service/resource existence + // 6. check service/resource check out + // 7. user is owner of checkout state + org.openecomp.sdc.be.model.Component component = null; + // ComponentInstance resourceInstance = null; + String realComponentId = componentType == ComponentTypeEnum.RESOURCE_INSTANCE ? parentId : componentId; + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(realComponentId, userId, auditingAction, user, artifactId, componentType, containerComponentType, inTransaction); + if (validateComponent.isRight()) { + return Either.right(validateComponent.right().value()); + } + component = validateComponent.left().value(); + Either<Boolean, ResponseFormat> validateWorkOnResource = validateWorkOnComponent(component, userId, auditingAction, user, artifactId, operation, componentType); + if (validateWorkOnResource.isRight()) { + return Either.right(validateWorkOnResource.right().value()); + } + // step 8 + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> result = validateAndHandleArtifact(componentId, componentType, operation, artifactId, artifactInfo, origMd5, originData, interfaceName, operationName, parentId, user, component, + shouldLock, inTransaction); + + return result; + } + + /** + * This Method validates only the Artifact and does not validate user / role / component ect...<br> + * For regular usage use <br> + * {@link #handleArtifactRequest(String, String, ComponentTypeEnum, ArtifactOperation, String, ArtifactDefinition, String, String, String, String, String, String)} + * + * @return + */ + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> validateAndHandleArtifact(String componentUniqueId, ComponentTypeEnum componentType, ArtifactOperation operation, String artifactUniqueId, ArtifactDefinition artifactDefinition, + String origMd5, String originData, String interfaceName, String operationName, String parentId, User user, Component component, boolean shouldLock, boolean inTransaction) { + Component parent = component; + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + + AuditingActionEnum auditingAction = detectAuditingType(operation, origMd5); + artifactDefinition = validateArtifact(componentUniqueId, componentType, operation, artifactUniqueId, artifactDefinition, parentId, auditingAction, user, component, parent, shouldLock, errorWrapper); + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> result; + if (errorWrapper.isEmpty()) { + // step 10 + result = doAction(componentUniqueId, componentType, operation, artifactUniqueId, artifactDefinition, origMd5, originData, interfaceName, operationName, auditingAction, user, parent, shouldLock, inTransaction); + } else { + result = Either.right(errorWrapper.getInnerElement()); + } + return result; + } + + private ArtifactDefinition validateArtifact(String componentId, ComponentTypeEnum componentType, ArtifactOperation operation, String artifactId, ArtifactDefinition artifactInfo, String parentId, AuditingActionEnum auditingAction, User user, + org.openecomp.sdc.be.model.Component component, org.openecomp.sdc.be.model.Component parent, boolean shouldLock, Wrapper<ResponseFormat> errorWrapper) { + if (operation == ArtifactOperation.Update || operation == ArtifactOperation.Delete || operation == ArtifactOperation.Download) { + Either<ArtifactDefinition, ResponseFormat> validateArtifact = validateArtifact(componentId, componentType, artifactId, component, auditingAction, parentId); + if (validateArtifact.isRight()) { + ResponseFormat responseFormat = validateArtifact.right().value(); + handleAuditing(auditingAction, parent, componentId, user, null, null, artifactId, responseFormat, componentType, null); + errorWrapper.setInnerElement(validateArtifact.right().value()); + } else if (operation == ArtifactOperation.Download) { + artifactInfo = validateArtifact.left().value(); + handleHeatEnvDownload(componentId, user, component, validateArtifact, shouldLock, errorWrapper); + } + } + return artifactInfo; + } + + private void handleHeatEnvDownload(String componentId, User user, org.openecomp.sdc.be.model.Component component, Either<ArtifactDefinition, ResponseFormat> validateArtifact, boolean shouldLock, Wrapper<ResponseFormat> errorWrapper) { + ArtifactDefinition validatedArtifact = validateArtifact.left().value(); + + if (validatedArtifact.getArtifactType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_ENV.getType())) { + ComponentInstance componentInstance = component.getComponentInstances().stream().filter(p -> p.getUniqueId().equals(componentId)).findAny().get(); + ArtifactDefinition heatEnvWithHeatParams = componentInstance.getDeploymentArtifacts().values().stream().filter(p -> p.getUniqueId().equals(validatedArtifact.getUniqueId())).findAny().get(); + Either<ArtifactDefinition, ResponseFormat> eitherGenerated = generateHeatEnvArtifact(heatEnvWithHeatParams, component, componentInstance.getName(), user, shouldLock); + if (eitherGenerated.isRight()) { + errorWrapper.setInnerElement(eitherGenerated.right().value()); + } + } + } + + private boolean artifactGenerationRequired(org.openecomp.sdc.be.model.Component component, ArtifactDefinition artifactInfo) { + return artifactInfo.getArtifactGroupType() == ArtifactGroupTypeEnum.TOSCA && (component.getLifecycleState() == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || component.getLifecycleState() == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> generateAndSaveToscaArtifact(ArtifactDefinition artifactDefinition, org.openecomp.sdc.be.model.Component component, User user, boolean isInCertificationRequest, + boolean shouldLock, boolean inTransaction, boolean fetchTemplatesFromDB) { + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> generated = generateToscaArtifact(component, artifactDefinition, isInCertificationRequest, fetchTemplatesFromDB, shouldLock, inTransaction); + if (generated.isRight()) { + return generated; + } + byte[] decodedPayload = artifactDefinition.getPayloadData(); + artifactDefinition.setEsId(artifactDefinition.getUniqueId()); + artifactDefinition.setArtifactChecksum(GeneralUtility.calculateMD5ByByteArray(decodedPayload)); + return lockComponentAndUpdateArtifact(component.getUniqueId(), artifactDefinition, AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE, artifactDefinition.getUniqueId(), user, component.getComponentType(), component, decodedPayload, null, null, + shouldLock, inTransaction); + + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> generateToscaArtifact(Component parent, ArtifactDefinition artifactInfo, boolean isInCertificationRequest, boolean fetchTemplatesFromDB, boolean shouldLock, + boolean inTransaction) { + log.debug("tosca artifact generation"); + if (artifactInfo.getArtifactType().equals(ArtifactTypeEnum.TOSCA_CSAR.getType())) { + Either<byte[], ResponseFormat> generated = csarUtils.createCsar(parent, fetchTemplatesFromDB, isInCertificationRequest, shouldLock, inTransaction); + + if (generated.isRight()) { + log.debug("Failed to export tosca csar for component {} error {}", parent.getUniqueId(), generated.right().value()); + + return Either.right(generated.right().value()); + } + byte[] value = generated.left().value(); + artifactInfo.setPayload(value); + + } else { + Either<ToscaRepresentation, ToscaError> exportComponent = toscaExportUtils.exportComponent(parent); + if (exportComponent.isRight()) { + log.debug("Failed export tosca yaml for component {} error {}", parent.getUniqueId(), exportComponent.right().value()); + ActionStatus status = componentsUtils.convertFromToscaError(exportComponent.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(status); + return Either.right(responseFormat); + } + log.debug("Tosca yaml exported for component {} ", parent.getUniqueId()); + String payload = exportComponent.left().value().getMainYaml(); + artifactInfo.setPayloadData(payload); + } + return Either.left(Either.left(artifactInfo)); + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> doAction(String componentId, ComponentTypeEnum componentType, ArtifactOperation operation, String artifactId, ArtifactDefinition artifactInfo, String origMd5, + String originData, String interfaceName, String operationName, AuditingActionEnum auditingAction, User user, org.openecomp.sdc.be.model.Component parent, boolean shouldLock, boolean inTransaction) { + if (interfaceName != null && operationName != null) { + interfaceName = interfaceName.toLowerCase(); + operationName = operationName.toLowerCase(); + } + switch (operation) { + case Download: + if (artifactGenerationRequired(parent, artifactInfo)) { + return generateToscaArtifact(parent, artifactInfo, false, false, shouldLock, inTransaction); + } + return handleDownload(componentId, artifactId, user, auditingAction, componentType, parent, shouldLock, inTransaction); + case Delete: + return handleDelete(componentId, artifactId, user, auditingAction, componentType, parent, interfaceName, operationName, shouldLock, inTransaction); + case Update: + ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifactInfo.getArtifactType()); + if (componentType.equals(ComponentTypeEnum.RESOURCE_INSTANCE) + && (artifactType == ArtifactTypeEnum.HEAT || artifactType == ArtifactTypeEnum.HEAT_VOL || artifactType == ArtifactTypeEnum.HEAT_NET || artifactType == ArtifactTypeEnum.HEAT_ENV)) { + return handleUpdateHeatEnv(componentId, artifactInfo, auditingAction, artifactId, user, componentType, parent, originData, origMd5, operation, shouldLock, inTransaction); + } + return handleUpdate(componentId, artifactInfo, operation, auditingAction, artifactId, user, componentType, parent, origMd5, originData, interfaceName, operationName, shouldLock, inTransaction); + case Create: + return handleCreate(componentId, artifactInfo, operation, auditingAction, user, componentType, parent, origMd5, originData, interfaceName, operationName, shouldLock, inTransaction); + } + return null; + } + + /** + * + * @param componentId + * @param artifactId + * @param userId + * @param componentType + * @param parentId + * TODO + * @return + */ + + public Either<ImmutablePair<String, byte[]>, ResponseFormat> handleDownloadToscaModelRequest(Component component, ArtifactDefinition csarArtifact, boolean shouldLock, boolean inTransaction) { + if (artifactGenerationRequired(component, csarArtifact)) { + Either<byte[], ResponseFormat> generated = csarUtils.createCsar(component, false, false, shouldLock, inTransaction); + + if (generated.isRight()) { + log.debug("Failed to export tosca csar for component {} error {}", component.getUniqueId(), generated.right().value()); + + return Either.right(generated.right().value()); + } + return Either.left(new ImmutablePair<String, byte[]>(csarArtifact.getArtifactName(), generated.left().value())); + } + return downloadArtifact(csarArtifact); + } + + public Either<ImmutablePair<String, byte[]>, ResponseFormat> handleDownloadRequestById(String componentId, String artifactId, String userId, ComponentTypeEnum componentType, String parentId, String containerComponentType) { + // perform all validation in common flow + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> result = handleArtifactRequest(componentId, userId, componentType, ArtifactOperation.Download, artifactId, null, null, null, null, null, parentId, containerComponentType); + if (result.isRight()) { + return Either.right(result.right().value()); + } + ArtifactDefinition artifactDefinition; + Either<ArtifactDefinition, Operation> insideValue = result.left().value(); + if (insideValue.isLeft()) { + artifactDefinition = insideValue.left().value(); + } else { + artifactDefinition = insideValue.right().value().getImplementation(); + } + // for tosca artifacts generated on download without saving + if (artifactDefinition.getArtifactGroupType() == ArtifactGroupTypeEnum.TOSCA && artifactDefinition.getPayloadData() != null) { + return Either.left(new ImmutablePair<String, byte[]>(artifactDefinition.getArtifactName(), artifactDefinition.getPayloadData())); + } + return downloadArtifact(artifactDefinition); + } + + private Either<ArtifactDefinition, ResponseFormat> validateArtifact(String componentId, ComponentTypeEnum componentType, String artifactId, org.openecomp.sdc.be.model.Component component, AuditingActionEnum auditingAction, String parentId) { + // step 9 + // check artifact existence + Either<ArtifactDefinition, StorageOperationStatus> artifactResult = artifactOperation.getArtifactById(artifactId, false); + if (artifactResult.isRight()) { + if (artifactResult.right().value().equals(StorageOperationStatus.ARTIFACT_NOT_FOUND)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, ""); + log.debug("addArtifact - artifact {} not found", artifactId); + return Either.right(responseFormat); + + } else { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(artifactResult.right().value())); + log.debug("addArtifact - failed to fetch artifact {}, error {}", artifactId, artifactResult.right().value()); + return Either.right(responseFormat); + } + } + // step 9.1 + // check artifact belong to component + boolean found = false; + switch (componentType) { + case RESOURCE: + case SERVICE: + found = checkArtifactInComponent(component, artifactId); + break; + case RESOURCE_INSTANCE: + found = checkArtifactInResourceInstance(component, componentId, artifactId); + break; + default: + + } + if (!found) { + // String component = + // componentType.equals(ComponentTypeEnum.RESOURCE) ? "resource" : + // "service"; + String componentName = componentType.name().toLowerCase(); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ARTIFACT_NOT_FOUND, componentName); + log.debug("addArtifact - Component artifact not found component Id {}, artifact id {}", componentId, artifactId); + return Either.right(responseFormat); + } + return Either.left(artifactResult.left().value()); + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleCreate(String parentId, ArtifactDefinition artifactInfo, ArtifactOperation operation, AuditingActionEnum auditingAction, User user, ComponentTypeEnum componentType, + org.openecomp.sdc.be.model.Component parent, String origMd5, String originData, String interfaceType, String operationName, boolean shouldLock, boolean inTransaction) { + + String artifactId = null; + + // step 11 + Either<byte[], ResponseFormat> payloadEither = validateInput(parentId, artifactInfo, operation, auditingAction, artifactId, user, componentType, parent, origMd5, originData, interfaceType, operationName, inTransaction); + if (payloadEither.isRight()) { + return Either.right(payloadEither.right().value()); + } + byte[] decodedPayload = payloadEither.left().value(); + NodeTypeEnum parentType = convertParentType(componentType); + // lock resource + + if (shouldLock) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(parent, "Upload Artifact - lock "); + if (lockComponent.isRight()) { + handleAuditing(auditingAction, parent, parentId, user, null, null, null, lockComponent.right().value(), componentType, null); + return Either.right(lockComponent.right().value()); + } + } + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + + try { + resultOp = createArtifact(parent, parentId, artifactInfo, decodedPayload, user, componentType, auditingAction, interfaceType, operationName); + return resultOp; + } finally { + if (shouldLock) { + unlockComponent(resultOp, parent, inTransaction); + } + + } + + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> lockComponentAndUpdateArtifact(String parentId, ArtifactDefinition artifactInfo, AuditingActionEnum auditingAction, String artifactId, User user, + ComponentTypeEnum componentType, org.openecomp.sdc.be.model.Component parent, byte[] decodedPayload, String interfaceType, String operationName, boolean shouldLock, boolean inTransaction) { + + NodeTypeEnum parentType = convertParentType(componentType); + + // lock resource + if (shouldLock) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(parent, "Update Artifact - lock "); + if (lockComponent.isRight()) { + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, lockComponent.right().value(), componentType, null); + return Either.right(lockComponent.right().value()); + } + } + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + try { + resultOp = updateArtifactFlow(parent, parentId, artifactId, artifactInfo, user, decodedPayload, componentType, auditingAction, interfaceType, operationName); + return resultOp; + + } finally { + if (shouldLock) { + unlockComponent(resultOp, parent, inTransaction); + } + } + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleUpdate(String parentId, ArtifactDefinition artifactInfo, ArtifactOperation operation, AuditingActionEnum auditingAction, String artifactId, User user, + ComponentTypeEnum componentType, org.openecomp.sdc.be.model.Component parent, String origMd5, String originData, String interfaceType, String operationName, boolean shouldLock, boolean inTransaction) { + + Either<byte[], ResponseFormat> payloadEither = validateInput(parentId, artifactInfo, operation, auditingAction, artifactId, user, componentType, parent, origMd5, originData, interfaceType, operationName, inTransaction); + + if (payloadEither.isRight()) { + return Either.right(payloadEither.right().value()); + } + byte[] decodedPayload = payloadEither.left().value(); + + return lockComponentAndUpdateArtifact(parentId, artifactInfo, auditingAction, artifactId, user, componentType, parent, decodedPayload, interfaceType, operationName, shouldLock, inTransaction); + } + + private Either<byte[], ResponseFormat> validateInput(String parentId, ArtifactDefinition artifactInfo, ArtifactOperation operation, AuditingActionEnum auditingAction, String artifactId, User user, ComponentTypeEnum componentType, + org.openecomp.sdc.be.model.Component parent, String origMd5, String originData, String interfaceType, String operationName, boolean inTransaction) { + // Md5 validations + Either<Boolean, ResponseFormat> validateMd5 = validateMd5(origMd5, originData, artifactInfo.getPayloadData(), operation); + if (validateMd5.isRight()) { + ResponseFormat responseFormat = validateMd5.right().value(); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + + // step 11 + Either<ArtifactDefinition, ResponseFormat> validateResult = validateInput(parentId, artifactInfo, operation, artifactId, user, interfaceType, operationName, componentType, parent, inTransaction); + if (validateResult.isRight()) { + ResponseFormat responseFormat = validateResult.right().value(); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(validateResult.right().value()); + } + + Either<byte[], ResponseFormat> payloadEither = handlePayload(artifactInfo, isArtifactMetadataUpdate(auditingAction)); + if (payloadEither.isRight()) { + ResponseFormat responseFormat = payloadEither.right().value(); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + log.debug("Error during handle payload"); + return Either.right(responseFormat); + } + + // validate heat parameters. this part must be after the parameters are + // extracted in "handlePayload" + Either<ArtifactDefinition, ResponseFormat> validateAndConvertHeatParamers = validateAndConvertHeatParamers(artifactInfo, artifactInfo.getArtifactType()); + if (validateAndConvertHeatParamers.isRight()) { + ResponseFormat responseFormat = validateAndConvertHeatParamers.right().value(); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, null, artifactId, responseFormat, componentType, null); + log.debug("Error during handle payload"); + return Either.right(responseFormat); + } + return payloadEither; + } + + public void handleAuditing(AuditingActionEnum auditingActionEnum, Component component, String componentId, User user, ArtifactDefinition artifactDefinition, String prevArtifactUuid, String currentArtifactUuid, ResponseFormat responseFormat, + ComponentTypeEnum componentTypeEnum, String resourceInstanceName) { + + if (auditingActionEnum.getAuditingEsType().equals(AuditingTypesConstants.EXTERNAL_API_EVENT_TYPE)) { + return; + } + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = createArtifactAuditingFields(artifactDefinition, prevArtifactUuid, currentArtifactUuid); + + if (user == null) { + user = new User(); + user.setUserId("UNKNOWN"); + } + switch (componentTypeEnum) { + + case RESOURCE: + Resource resource = (Resource) component; + if (resource == null) { + // In that case, component ID should be instead of name + resource = new Resource(); + resource.setName(componentId); + } + componentsUtils.auditResource(responseFormat, user, resource, null, null, auditingActionEnum, auditingFields); + break; + + case SERVICE: + Service service = (Service) component; + if (service == null) { + // In that case, component ID should be instead of name + service = new Service(); + service.setName(componentId); + } + componentsUtils.auditComponent(responseFormat, user, service, null, null, auditingActionEnum, ComponentTypeEnum.SERVICE, auditingFields); + break; + + case RESOURCE_INSTANCE: + if (resourceInstanceName == null) { + resourceInstanceName = getResourceInstanceNameFromComponent(component, componentId); + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInstanceName); + componentsUtils.auditComponent(responseFormat, user, component, null, null, auditingActionEnum, ComponentTypeEnum.RESOURCE_INSTANCE, auditingFields); + + break; + default: + break; + } + } + + private String getResourceInstanceNameFromComponent(Component component, String componentId) { + ComponentInstance resourceInstance = component.getComponentInstances().stream().filter(p -> p.getUniqueId().equals(componentId)).findFirst().orElse(null); + String resourceInstanceName = null; + if (resourceInstance != null) { + resourceInstanceName = resourceInstance.getName(); + } + return resourceInstanceName; + } + + public EnumMap<AuditingFieldsKeysEnum, Object> createArtifactAuditingFields(ArtifactDefinition artifactDefinition, String prevArtifactUuid, String currentArtifactUuid) { + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + // Putting together artifact info + String artifactData = buildAuditingArtifactData(artifactDefinition); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ARTIFACT_DATA, artifactData); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_PREV_ARTIFACT_UUID, prevArtifactUuid); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_CURR_ARTIFACT_UUID, currentArtifactUuid); + return auditingFields; + } + + // ----- + + private String buildAuditingArtifactData(ArtifactDefinition artifactDefinition) { + StringBuilder sb = new StringBuilder(); + if (artifactDefinition != null) { + sb.append(artifactDefinition.getArtifactGroupType().getType()).append(",").append("'").append(artifactDefinition.getArtifactLabel()).append("'").append(",").append(artifactDefinition.getArtifactType()).append(",") + .append(artifactDefinition.getArtifactName()).append(",").append(artifactDefinition.getTimeout()).append(",").append(artifactDefinition.getEsId()); + + sb.append(","); + if (artifactDefinition.getArtifactVersion() != null) { + + sb.append(artifactDefinition.getArtifactVersion()); + } else { + sb.append(" "); + } + sb.append(","); + if (artifactDefinition.getArtifactUUID() != null) { + sb.append(artifactDefinition.getArtifactUUID()); + } else { + sb.append(" "); + } + } + return sb.toString(); + } + + private Either<Boolean, ResponseFormat> validateMd5(String origMd5, String originData, byte[] payload, ArtifactOperation operation) { + + if (origMd5 != null) { + String encodeBase64Str = GeneralUtility.calculateMD5ByString(originData); + + if (false == encodeBase64Str.equals(origMd5)) { + log.debug("The calculated md5 is different then the received one"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_INVALID_MD5)); + } + } else { + if (operation == ArtifactOperation.Create) { + log.debug("Missing md5 header during artifact create"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_INVALID_MD5)); + } + // Update metadata + if (payload != null && payload.length != 0) { + log.debug("Cannot have payload while md5 header is missing"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + } + return Either.left(true); + } + + private Either<ArtifactDefinition, ResponseFormat> validateInput(String parentId, ArtifactDefinition artifactInfo, ArtifactOperation operation, String artifactId, User user, String interfaceName, String operationName, + ComponentTypeEnum componentType, Component parentComponent, boolean inTransaction) { + + Either<Boolean, ResponseFormat> validateAndSetArtifactname = validateAndSetArtifactname(artifactInfo); + if (validateAndSetArtifactname.isRight()) { + return Either.right(validateAndSetArtifactname.right().value()); + } + Either<ArtifactDefinition, ResponseFormat> artifactById = fetchCurrentArtifact(operation, artifactId); + if (artifactById.isRight()) { + return Either.right(artifactById.right().value()); + } + ArtifactDefinition currentArtifactInfo = artifactById.left().value(); + if (operationName != null && interfaceName != null) { + operationName = operationName.toLowerCase(); + interfaceName = interfaceName.toLowerCase(); + } + Either<ActionStatus, ResponseFormat> logicalNameStatus = handleArtifactLabel(parentId, operation, artifactId, artifactInfo, interfaceName, operationName, currentArtifactInfo, componentType, inTransaction); + if (logicalNameStatus.isRight()) { + return Either.right(logicalNameStatus.right().value()); + } + // This is a patch to block possibility of updating service api fields + // through other artifacts flow + + if (!operation.equals(ArtifactOperation.Create)) { + checkAndSetUnUpdatableFields(user, artifactInfo, currentArtifactInfo, (operationName != null ? ArtifactGroupTypeEnum.LIFE_CYCLE : ArtifactGroupTypeEnum.INFORMATIONAL)); + } else { + checkCreateFields(user, artifactInfo, (operationName != null ? ArtifactGroupTypeEnum.LIFE_CYCLE : ArtifactGroupTypeEnum.INFORMATIONAL)); + } + + composeArtifactId(parentId, artifactId, artifactInfo, interfaceName, operationName); + if (currentArtifactInfo != null) { + artifactInfo.setMandatory(currentArtifactInfo.getMandatory()); + } + + // artifactGroupType is not allowed to be updated + if (!operation.equals(ArtifactOperation.Create)) { + Either<ArtifactDefinition, ResponseFormat> validateGroupType = validateOrSetArtifactGroupType(artifactInfo, currentArtifactInfo); + if (validateGroupType.isRight()) { + return Either.right(validateGroupType.right().value()); + } + } + // TODO TEMP !!! + NodeTypeEnum parentType = convertParentType(componentType); + + // TODO TEMP !!! + boolean isCreate = operation.equals(ArtifactOperation.Create); + + if (isDeploymentArtifact(artifactInfo)) { + Either<Boolean, ResponseFormat> deploymentValidationResult = validateDeploymentArtifact(parentComponent, parentId, user.getUserId(), isCreate, artifactInfo, currentArtifactInfo, parentType); + if (deploymentValidationResult.isRight()) { + return Either.right(deploymentValidationResult.right().value()); + } + } else { + artifactInfo.setTimeout(NON_HEAT_TIMEOUT); + + /* + * if (informationDeployedArtifactsBusinessLogic. isInformationDeployedArtifact(artifactInfo)) { Either<Boolean, ResponseFormat> validationResult = informationDeployedArtifactsBusinessLogic.validateArtifact( isCreate, artifactInfo, + * parentComponent, parentType); if (validationResult.isRight()) { return Either.right(validationResult.right().value()); } } + */ + } + + Either<Boolean, ResponseFormat> descriptionResult = validateAndCleanDescription(artifactInfo); + if (descriptionResult.isRight()) { + return Either.right(descriptionResult.right().value()); + } + + if (currentArtifactInfo != null && currentArtifactInfo.getArtifactGroupType().equals(ArtifactGroupTypeEnum.SERVICE_API)) { + Either<ActionStatus, ResponseFormat> validateServiceApiType = validateArtifactType(user.getUserId(), artifactInfo, parentType); + if (validateServiceApiType.isRight()) { + return Either.right(validateServiceApiType.right().value()); + } + // Change of type is not allowed and should be ignored + + artifactInfo.setArtifactType(ARTIFACT_TYPE_OTHER); + + Either<Boolean, ResponseFormat> validateUrl = validateAndServiceApiUrl(artifactInfo); + if (validateUrl.isRight()) { + return Either.right(validateUrl.right().value()); + } + + Either<Boolean, ResponseFormat> validateUpdate = validateFirstUpdateHasPayload(artifactInfo, currentArtifactInfo); + if (validateUpdate.isRight()) { + log.debug("serviceApi first update cnnot be without payload."); + return Either.right(validateUpdate.right().value()); + } + } else { + Either<ActionStatus, ResponseFormat> validateArtifactType = validateArtifactType(user.getUserId(), artifactInfo, parentType); + if (validateArtifactType.isRight()) { + return Either.right(validateArtifactType.right().value()); + } + if (artifactInfo.getApiUrl() != null) { + artifactInfo.setApiUrl(null); + log.error("Artifact URL cannot be set through this API - ignoring"); + } + + if (artifactInfo.getServiceApi() != null) { + if (artifactInfo.getServiceApi()) { + artifactInfo.setServiceApi(false); + log.error("Artifact service API flag cannot be changed - ignoring"); + } + } + } + + return Either.left(artifactInfo); + } + + private NodeTypeEnum convertParentType(ComponentTypeEnum componentType) { + if (componentType.equals(ComponentTypeEnum.RESOURCE)) { + return NodeTypeEnum.Resource; + } else if (componentType.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + return NodeTypeEnum.ResourceInstance; + } else { + return NodeTypeEnum.Service; + } + } + + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDelete(String parentId, String artifactId, User user, AuditingActionEnum auditingAction, ComponentTypeEnum componentType, org.openecomp.sdc.be.model.Component parent, + String interfaceType, String operationName, boolean shouldLock, boolean inTransaction) { + NodeTypeEnum parentType = convertParentType(componentType); + // lock resource + if (shouldLock) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(parent, "Delete Artifact - lock resource: "); + if (lockComponent.isRight()) { + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, lockComponent.right().value(), componentType, null); + return Either.right(lockComponent.right().value()); + } + } + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + Either<ArtifactDefinition, Operation> insideEither = null; + StorageOperationStatus error = null; + boolean isLeft = false; + ArtifactDefinition artifactDefinition = null; + Integer artifactParentsCount = 1; + try { + if (interfaceType != null && operationName != null) { + log.debug("Try to delete inteface lifecycle artifact {}", artifactId); + + Either<Operation, StorageOperationStatus> result = interfaceLifecycleOperation.deleteInterfaceOperation(parentId, interfaceType, UniqueIdBuilder.buildOperationByInterfaceUniqueId(parentId, interfaceType, operationName), + inTransaction); + isLeft = result.isLeft(); + if (isLeft) { + artifactDefinition = result.left().value().getImplementation(); + insideEither = Either.right(result.left().value()); + } + } else { + log.debug("Try to delete artifact, get parents {}", artifactId); + + Either<Integer, StorageOperationStatus> parentsOfArtifact = artifactOperation.getParentsOfArtifact(artifactId, parentType); + if (parentsOfArtifact.isRight()) { + log.debug("Failed to delete entry on graph for artifact {}", artifactId); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(parentsOfArtifact.right().value()), ""); + resultOp = Either.right(responseFormat); + } else { + + artifactParentsCount = parentsOfArtifact.left().value(); + log.debug("Number of parents nodes on graph for artifact {} is {}", artifactId, artifactParentsCount); + + Either<ArtifactDefinition, StorageOperationStatus> result = artifactOperation.removeArifactFromResource(parentId, artifactId, parentType, false, true); + isLeft = result.isLeft(); + if (isLeft) { + log.debug("Artifact removed from graph {}", artifactId); + + artifactDefinition = result.left().value(); + insideEither = Either.left(result.left().value()); + } else { + error = result.right().value(); + } + } + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + if (isLeft) { + StorageOperationStatus deleteIfNotOnGraph = StorageOperationStatus.OK; + if (artifactParentsCount < 2) { + log.debug("Number of parent nodes is 1. Need to delete from ES {}", artifactId); + deleteIfNotOnGraph = deleteIfNotOnGraph(artifactId, artifactDefinition.getEsId(), true); + } + if (deleteIfNotOnGraph.equals(StorageOperationStatus.OK)) { + if (artifactDefinition.getMandatory() || artifactDefinition.getServiceApi()) { + log.debug("Artifact is mandatory or service API. Clean all fields for {}", artifactId); + artifactDefinition.setEsId(""); + artifactDefinition.setArtifactName(""); + artifactDefinition.setDescription(""); + artifactDefinition.setApiUrl(""); + artifactDefinition.setArtifactChecksum(""); + setDefaultArtifactTimeout(artifactDefinition.getArtifactGroupType(), artifactDefinition); + artifactDefinition.setArtifactUUID(""); + long time = System.currentTimeMillis(); + artifactDefinition.setPayloadUpdateDate(time); + artifactDefinition.setHeatParameters(null); + artifactDefinition.setHeatParamsUpdateDate(null); + Either<ArtifactDefinition, StorageOperationStatus> resStatus = null; + if (artifactParentsCount < 2) { + log.debug("Only one parent , clean existing placeholder for {}", artifactId); + resStatus = artifactOperation.updateArifactOnResource(artifactDefinition, parentId, artifactId, parentType, true); + } else { + log.debug("more than one parent , create new placeholder for {}", artifactId); + artifactDefinition.setUniqueId(null); + resStatus = artifactOperation.addArifactToComponent(artifactDefinition, parentId, parentType, true, true); + } + if (resStatus.isRight()) { + log.debug("Failed to clean placeholder for {}", artifactId); + responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(resStatus.right().value()), artifactDefinition.getArtifactDisplayName()); + resultOp = Either.right(responseFormat); + } else { + log.debug("Placeholder was cleaned for {}", artifactId); + + ArtifactDefinition artifactUfterChange = resStatus.left().value(); + + insideEither = Either.left(artifactUfterChange); + resultOp = Either.left(insideEither); + } + } else { + log.debug("Artifact isn't mandatory/service API. Removed. {}", artifactId); + resultOp = Either.left(insideEither); + } + + } else { + log.debug("failed to delete artifact from ES {} status {}", artifactId, deleteIfNotOnGraph); + responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(deleteIfNotOnGraph), artifactDefinition.getArtifactDisplayName()); + resultOp = Either.right(responseFormat); + } + } else { + log.debug("Failed to delete entry on graph for artifact {}", artifactId); + responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(error), ""); + resultOp = Either.right(responseFormat); + } + handleAuditing(auditingAction, parent, parentId, user, artifactDefinition, null, artifactId, responseFormat, componentType, null); + return resultOp; + } finally { + if (shouldLock) { + unlockComponent(resultOp, parent, inTransaction); + } + } + + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDownload(String componentId, String artifactId, User user, AuditingActionEnum auditingAction, ComponentTypeEnum componentType, + org.openecomp.sdc.be.model.Component parent, boolean shouldLock, boolean inTransaction) { + Either<ArtifactDefinition, StorageOperationStatus> artifactById = artifactOperation.getArtifactById(artifactId, false); + if (artifactById.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(artifactById.right().value()); + log.debug("Error when getting artifact info by id{}, error: {}", artifactId, actionStatus.name()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(actionStatus, ""); + handleAuditing(auditingAction, parent, componentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + ArtifactDefinition artifactDefinition = artifactById.left().value(); + if (artifactDefinition == null) { + log.debug("Empty artifact definition returned from DB by artifact id {}", artifactId); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, ""); + handleAuditing(auditingAction, parent, componentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + Either<ArtifactDefinition, Operation> insideEither = Either.left(artifactDefinition); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleAuditing(auditingAction, parent, componentId, user, artifactDefinition, null, artifactId, responseFormat, componentType, null); + return Either.left(insideEither); + } + + private Either<ArtifactDefinition, ResponseFormat> fetchCurrentArtifact(ArtifactOperation operation, String artifactId) { + Either<ArtifactDefinition, StorageOperationStatus> artifactById = artifactOperation.getArtifactById(artifactId, true); + if (!operation.equals(ArtifactOperation.Create) && artifactById.isRight()) { + // in case of update artifact must be + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeArtifactMissingError, "Artifact Update / Upload", artifactId); + BeEcompErrorManager.getInstance().logBeArtifactMissingError("Artifact Update / Upload", artifactId); + log.debug("Failed to fetch artifact {}. error: {}", artifactId, artifactById.right().value()); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(artifactById.right().value()), artifactId)); + } + if (operation.equals(ArtifactOperation.Create) && artifactById.isLeft()) { + log.debug("Artifact {} already exist", artifactId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_EXIST, artifactById.left().value().getArtifactLabel())); + } + ArtifactDefinition currentArtifactInfo = null; + if (artifactById.isLeft()) { + // get previous value + currentArtifactInfo = artifactById.left().value(); + } + return Either.left(currentArtifactInfo); + } + + private Either<ActionStatus, ResponseFormat> handleArtifactLabel(String componentId, ArtifactOperation operation, String artifactId, ArtifactDefinition artifactInfo, String interfaceName, String operationName, + ArtifactDefinition currentArtifactInfo, ComponentTypeEnum componentType, boolean inTransaction) { + String artifactLabel = artifactInfo.getArtifactLabel(); + + if (operationName == null && (artifactInfo.getArtifactLabel() == null || artifactInfo.getArtifactLabel().isEmpty())) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingArtifactInformationError, "Artifact Update / Upload", "artifactLabel"); + BeEcompErrorManager.getInstance().logBeMissingArtifactInformationError("Artifact Update / Upload", "artifactLabel"); + log.debug("missing artifact logical name for component {}", componentId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_LABEL)); + } + if (operation.equals(ArtifactOperation.Create) && !artifactInfo.getMandatory()) { + + if (operationName != null) { + if (artifactInfo.getArtifactLabel() != null && !operationName.equals(artifactInfo.getArtifactLabel())) { + log.debug("artifact label cannot be set {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED)); + } else { + artifactLabel = operationName; + } + } + String displayName = artifactInfo.getArtifactDisplayName(); + if (displayName == null || displayName.isEmpty()) + displayName = artifactLabel; + displayName = ValidationUtils.cleanArtifactDisplayName(displayName); + artifactInfo.setArtifactDisplayName(displayName); + + if (!ValidationUtils.validateArtifactLabel(artifactLabel)) { + log.debug("Invalid format form Artifact label : {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + artifactLabel = ValidationUtils.normalizeArtifactLabel(artifactLabel); + + if (artifactLabel.isEmpty()) { + log.debug("missing normalized artifact logical name for component {}", componentId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_LABEL)); + } + + if (!ValidationUtils.validateArtifactLabelLength(artifactLabel)) { + log.debug("Invalid lenght form Artifact label : {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, ARTIFACT_LABEL, String.valueOf(ValidationUtils.ARTIFACT_LABEL_LENGTH))); + } + if (!validateLabelUniqueness(componentId, artifactLabel, componentType, inTransaction)) { + log.debug("Non unique Artifact label : {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_EXIST, artifactLabel)); + } + } + artifactInfo.setArtifactLabel(artifactLabel); + + if (currentArtifactInfo != null && !currentArtifactInfo.getArtifactLabel().equals(artifactInfo.getArtifactLabel())) { + log.info("Logical artifact's name cannot be changed {}", artifactId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED)); + } + return Either.left(ActionStatus.OK); + } + + private boolean validateLabelUniqueness(String parentId, String artifactLabel, ComponentTypeEnum componentType, boolean inTransaction) { + boolean isUnique = true; + NodeTypeEnum parentType; + if (componentType.equals(ComponentTypeEnum.RESOURCE)) { + parentType = NodeTypeEnum.Resource; + } else { + parentType = NodeTypeEnum.Service; + } + Either<Map<String, ArtifactDefinition>, StorageOperationStatus> artifacts = artifactOperation.getArtifacts(parentId, parentType, inTransaction); + if (artifacts.isLeft()) { + for (String label : artifacts.left().value().keySet()) { + if (label.equals(artifactLabel)) { + isUnique = false; + break; + } + } + } + if (componentType.equals(ComponentTypeEnum.RESOURCE)) { + Either<Map<String, InterfaceDefinition>, StorageOperationStatus> allInterfacesOfResource = interfaceLifecycleOperation.getAllInterfacesOfResource(parentId, true, inTransaction); + if (allInterfacesOfResource.isLeft()) { + for (InterfaceDefinition interace : allInterfacesOfResource.left().value().values()) { + for (Operation operation : interace.getOperations().values()) { + if (operation.getImplementation() != null && operation.getImplementation().getArtifactLabel().equals(artifactLabel)) { + isUnique = false; + break; + } + } + } + } + } + return isUnique; + } + + // *************************************************************** + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> createArtifact(org.openecomp.sdc.be.model.Component parent, String parentId, ArtifactDefinition artifactInfo, byte[] decodedPayload, User user, + ComponentTypeEnum componentTypeEnum, AuditingActionEnum auditingActionEnum, String interfaceType, String operationName) { + + ESArtifactData artifactData = createEsArtifactData(artifactInfo, decodedPayload); + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + Either<ArtifactDefinition, Operation> insideEither = null; + + if (artifactData == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Upload Artifact"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Upload Artifact"); + log.debug("Failed to create artifact object for ES."); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + handleAuditing(auditingActionEnum, parent, parentId, user, artifactInfo, null, null, responseFormat, componentTypeEnum, null); + resultOp = Either.right(responseFormat); + return resultOp; + + } + // set on graph object id of artifact in ES! + artifactInfo.setEsId(artifactData.getId()); + + boolean isLeft = false; + String artifactUniqueId = null; + ArtifactDefinition artifactDefinition = null; + StorageOperationStatus error = null; + if (interfaceType != null && operationName != null) { + // lifecycle artifact + Operation operation = convertToOperation(artifactInfo, operationName); + + Either<Operation, StorageOperationStatus> result = interfaceLifecycleOperation.updateInterfaceOperation(parentId, interfaceType, operationName, operation); + + isLeft = result.isLeft(); + if (isLeft) { + artifactUniqueId = result.left().value().getImplementation().getUniqueId(); + artifactDefinition = result.left().value().getImplementation(); + + insideEither = Either.right(result.left().value()); + resultOp = Either.left(insideEither); + } else { + error = result.right().value(); + } + } else { + // information/deployment/api aritfacts + log.debug("Try to create entry on graph"); + NodeTypeEnum nodeType = convertParentType(componentTypeEnum); + Either<ArtifactDefinition, StorageOperationStatus> result = artifactOperation.addArifactToComponent(artifactInfo, parentId, nodeType, true, true); + + isLeft = result.isLeft(); + if (isLeft) { + artifactUniqueId = result.left().value().getUniqueId(); + artifactDefinition = result.left().value(); + + insideEither = Either.left(result.left().value()); + resultOp = Either.left(insideEither); + } else { + error = result.right().value(); + } + } + if (isLeft) { + boolean res = saveArtifacts(artifactData, parentId, false); + // String uniqueId = artifactDefinition.getUniqueId(); + + if (res) { + log.debug("Artifact saved into ES - {}", artifactUniqueId); + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleAuditing(auditingActionEnum, parent, parentId, user, artifactInfo, artifactUniqueId, artifactUniqueId, responseFormat, componentTypeEnum, null); + return resultOp; + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Upload Artifact"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Upload Artifact"); + log.debug("Failed to save the artifact."); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + handleAuditing(auditingActionEnum, parent, parentId, user, artifactInfo, null, artifactUniqueId, responseFormat, componentTypeEnum, null); + + resultOp = Either.right(responseFormat); + return resultOp; + } + } else { + log.debug("Failed to create entry on graph for artifact {}", artifactInfo.getArtifactName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(error), artifactInfo.getArtifactDisplayName()); + handleAuditing(auditingActionEnum, parent, parentId, user, artifactInfo, null, null, responseFormat, componentTypeEnum, null); + resultOp = Either.right(responseFormat); + return resultOp; + } + + } + + private Either<Boolean, ResponseFormat> validateDeploymentArtifact(Component parentComponent, String parentId, String userId, boolean isCreate, ArtifactDefinition artifactInfo, ArtifactDefinition currentArtifact, NodeTypeEnum parentType) { + + Either<Boolean, ResponseFormat> result = Either.left(true); + Wrapper<ResponseFormat> responseWrapper = new Wrapper<ResponseFormat>(); + + validateArtifactTypeExists(responseWrapper, artifactInfo); + + ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifactInfo.getArtifactType()); + + Map<String, DeploymentArtifactTypeConfig> resourceDeploymentArtifacts = fillDeploymentArtifactTypeConf(parentType); + + if (responseWrapper.isEmpty()) { + validateDeploymentArtifactConf(artifactInfo, responseWrapper, artifactType, resourceDeploymentArtifacts); + } + + if (responseWrapper.isEmpty()) { + // Common code for all types + // not allowed to change artifactType + if (!isCreate) { + Either<Boolean, ResponseFormat> validateServiceApiType = validateArtifactTypeNotChanged(artifactInfo, currentArtifact); + if (validateServiceApiType.isRight()) { + responseWrapper.setInnerElement(validateServiceApiType.right().value()); + } + } + } + if (responseWrapper.isEmpty()) { + if (parentType.equals(NodeTypeEnum.Resource)) { + // if (parentComponent instanceof Resource) { + Resource resource = (Resource) parentComponent; + ResourceTypeEnum resourceType = resource.getResourceType(); + DeploymentArtifactTypeConfig config = resourceDeploymentArtifacts.get(artifactType.getType()); + if (config == null) { + responseWrapper.setInnerElement(ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED, artifactInfo.getArtifactType())); + } else { + List<String> myList = config.getValidForResourceTypes(); + Either<Boolean, ResponseFormat> either = validateResourceType(resourceType, artifactInfo, myList); + if (either.isRight()) { + responseWrapper.setInnerElement(either.right().value()); + } + } + } + } + if (responseWrapper.isEmpty()) { + validateFileExtension(responseWrapper, () -> getDeploymentArtifactTypeConfig(parentType, artifactType), artifactInfo, parentType, artifactType); + } + + if (responseWrapper.isEmpty() && !NodeTypeEnum.ResourceInstance.equals(parentType)) { + String artifactName = artifactInfo.getArtifactName(); + if (isCreate || !artifactName.equalsIgnoreCase(currentArtifact.getArtifactName())) { + validateSingleDeploymentArtifactName(responseWrapper, artifactName, parentComponent, parentType); + } + } + + if (responseWrapper.isEmpty()) { + switch (artifactType) { + case HEAT: + case HEAT_VOL: + case HEAT_NET: { + result = validateHeatDeploymentArtifact(parentComponent, userId, isCreate, artifactInfo, currentArtifact, parentType); + break; + } + case HEAT_ENV: { + result = validateHeatEnvDeploymentArtifact(parentComponent, parentId, userId, isCreate, artifactInfo, parentType); + artifactInfo.setTimeout(NON_HEAT_TIMEOUT); + break; + } + case DCAE_INVENTORY_TOSCA: + case DCAE_INVENTORY_JSON: + case DCAE_INVENTORY_POLICY: + // Validation is done in handle payload. + case DCAE_INVENTORY_DOC: + case DCAE_INVENTORY_BLUEPRINT: + case DCAE_INVENTORY_EVENT: + // No specific validation + default: { + artifactInfo.setTimeout(NON_HEAT_TIMEOUT); + } + } + + } + + if (!responseWrapper.isEmpty()) { + result = Either.right(responseWrapper.getInnerElement()); + } + return result; + } + + private void validateDeploymentArtifactConf(ArtifactDefinition artifactInfo, Wrapper<ResponseFormat> responseWrapper, ArtifactTypeEnum artifactType, Map<String, DeploymentArtifactTypeConfig> resourceDeploymentArtifacts) { + if ((resourceDeploymentArtifacts == null) || !resourceDeploymentArtifacts.containsKey(artifactType.name())) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED, artifactInfo.getArtifactType()); + responseWrapper.setInnerElement(responseFormat); + log.debug("Artifact Type: {} Not found !", artifactInfo.getArtifactType()); + } + } + + private Map<String, DeploymentArtifactTypeConfig> fillDeploymentArtifactTypeConf(NodeTypeEnum parentType) { + Map<String, DeploymentArtifactTypeConfig> resourceDeploymentArtifacts = null; + if (parentType.equals(NodeTypeEnum.Resource)) { + resourceDeploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceDeploymentArtifacts(); + } else if (parentType.equals(NodeTypeEnum.ResourceInstance)) { + resourceDeploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceInstanceDeploymentArtifacts(); + } else { + resourceDeploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getServiceDeploymentArtifacts(); + } + return resourceDeploymentArtifacts; + } + + public void validateArtifactTypeExists(Wrapper<ResponseFormat> responseWrapper, ArtifactDefinition artifactInfo) { + ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifactInfo.getArtifactType()); + if (artifactType == null) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.GENERAL_ERROR); + responseWrapper.setInnerElement(responseFormat); + log.debug("Artifact Type: {} Not found !", artifactInfo.getArtifactType()); + } + } + + private DeploymentArtifactTypeConfig getDeploymentArtifactTypeConfig(NodeTypeEnum parentType, ArtifactTypeEnum artifactType) { + DeploymentArtifactTypeConfig retConfig = null; + String fileType = artifactType.getType(); + if (parentType.equals(NodeTypeEnum.Resource)) { + retConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceDeploymentArtifacts().get(fileType); + } else if (parentType.equals(NodeTypeEnum.Service)) { + retConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getServiceDeploymentArtifacts().get(fileType); + } else if (parentType.equals(NodeTypeEnum.ResourceInstance)) { + retConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceInstanceDeploymentArtifacts().get(fileType); + } + return retConfig; + } + + private Either<Boolean, ResponseFormat> extractHeatParameters(ArtifactDefinition artifactInfo) { + // extract heat parameters + if (artifactInfo.getPayloadData() != null) { + String heatDecodedPayload = GeneralUtility.isBase64Encoded(artifactInfo.getPayloadData()) ? new String(Base64.decodeBase64(artifactInfo.getPayloadData())) : new String(artifactInfo.getPayloadData()); + Either<List<HeatParameterDefinition>, ResultStatusEnum> heatParameters = ImportUtils.getHeatParamsWithoutImplicitTypes(heatDecodedPayload, artifactInfo.getArtifactType()); + if (heatParameters.isRight() && (!heatParameters.right().value().equals(ResultStatusEnum.ELEMENT_NOT_FOUND))) { + log.info("failed to parse heat parameters "); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT, artifactInfo.getArtifactType()); + return Either.right(responseFormat); + } else if (heatParameters.isLeft() && heatParameters.left().value() != null) { + artifactInfo.setHeatParameters(heatParameters.left().value()); + } + } + return Either.left(true); + + } + + // Valid extension + public void validateFileExtension(Wrapper<ResponseFormat> responseWrapper, IDeploymentArtifactTypeConfigGetter deploymentConfigGetter, ArtifactDefinition artifactInfo, NodeTypeEnum parentType, ArtifactTypeEnum artifactType) { + String fileType = artifactType.getType(); + List<String> acceptedTypes = null; + DeploymentArtifactTypeConfig deploymentAcceptedTypes = deploymentConfigGetter.getDeploymentArtifactConfig(); + if (!parentType.equals(NodeTypeEnum.Resource) && !parentType.equals(NodeTypeEnum.Service) && !parentType.equals(NodeTypeEnum.ResourceInstance)) { + log.debug("parent type of artifact can be either resource or service"); + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return; + } + + if (deploymentAcceptedTypes == null) { + log.debug("parent type of artifact can be either resource or service"); + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED, artifactInfo.getArtifactType())); + return; + } else { + acceptedTypes = deploymentAcceptedTypes.getAcceptedTypes(); + } + /* + * No need to check specific types. In case there are no acceptedTypes in configuration, then any type is accepted. + * + * if ((!artifactType.equals(ArtifactTypeEnum.OTHER) && !artifactType.equals(ArtifactTypeEnum.HEAT_ARTIFACT )) && (acceptedTypes == null || acceptedTypes.isEmpty()) ) { log.debug( "No accepted types found for type {}, parent type {}", + * fileType, parentType.getName()); String methodName = new Object() { }.getClass().getEnclosingMethod().getName(); String configEntryMissing = (parentType.equals(NodeTypeEnum.Resource)) ? "resourceDeploymentArtifacts:" + fileType : + * "serviceDeploymentArtifacts:" + fileType; BeEcompErrorManager.getInstance().processEcompError(EcompErrorName. BeMissingConfigurationError, methodName, configEntryMissing); BeEcompErrorManager.getInstance().logBeMissingConfigurationError( + * methodName, configEntryMissing); responseWrapper.setInnerElement(componentsUtils.getResponseFormat( ActionStatus.GENERAL_ERROR)); return; } + */ + + String artifactName = artifactInfo.getArtifactName(); + String fileExtension = GeneralUtility.getFilenameExtension(artifactName); + // Pavel - File extension validation is case-insensitive - Ella, + // 21/02/2016 + if (acceptedTypes != null && !acceptedTypes.isEmpty() && !acceptedTypes.contains(fileExtension.toLowerCase())) { + log.debug("File extension \"{}\" is not allowed for {} which is of type:{}", fileExtension, artifactName, fileType); + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION, fileType)); + return; + } + } + + private Either<Boolean, ResponseFormat> validateHeatEnvDeploymentArtifact(Component parentComponent, String parentId, String userId, boolean isCreate, ArtifactDefinition artifactInfo, NodeTypeEnum parentType) { + + Wrapper<ResponseFormat> errorWrapper = new Wrapper<ResponseFormat>(); + Wrapper<ArtifactDefinition> heatMDWrapper = new Wrapper<ArtifactDefinition>(); + Wrapper<byte[]> payloadWrapper = new Wrapper<>(); + + if (errorWrapper.isEmpty()) { + validateValidYaml(errorWrapper, artifactInfo); + } + + if (errorWrapper.isEmpty()) { + // Validate Heat Exist + validateHeatExist(artifactInfo.getUniqueId(), errorWrapper, heatMDWrapper, getDeploymentArtifacts(parentComponent, parentType, parentId)); + } + + if (errorWrapper.isEmpty() && isCreate) { + // Validate Only Single HeatEnv Artifact + validateSingleArtifactType(errorWrapper, ArtifactTypeEnum.HEAT_ENV, parentComponent, parentType, parentId); + } + + if (errorWrapper.isEmpty() && !heatMDWrapper.isEmpty()) { + fillArtifactPayloadValidation(errorWrapper, payloadWrapper, heatMDWrapper.getInnerElement()); + } + + if (errorWrapper.isEmpty() && !heatMDWrapper.isEmpty()) { + validateEnvVsHeat(errorWrapper, artifactInfo, heatMDWrapper.getInnerElement(), payloadWrapper.getInnerElement()); + } + + // Init Response + Either<Boolean, ResponseFormat> eitherResponse; + if (errorWrapper.isEmpty()) { + eitherResponse = Either.left(true); + } else { + eitherResponse = Either.right(errorWrapper.getInnerElement()); + } + return eitherResponse; + } + + public void fillArtifactPayloadValidation(Wrapper<ResponseFormat> errorWrapper, Wrapper<byte[]> payloadWrapper, ArtifactDefinition artifactDefinition) { + if (artifactDefinition.getPayloadData() == null || artifactDefinition.getPayloadData().length == 0) { + Either<Boolean, ResponseFormat> fillArtifactPayload = fillArtifactPayload(payloadWrapper, artifactDefinition); + if (fillArtifactPayload.isRight()) { + errorWrapper.setInnerElement(fillArtifactPayload.right().value()); + log.debug("Error getting payload for artifact:{}", artifactDefinition.getArtifactName()); + } + } else { + payloadWrapper.setInnerElement(artifactDefinition.getPayloadData()); + } + } + + public Either<Boolean, ResponseFormat> fillArtifactPayload(Wrapper<byte[]> payloadWrapper, ArtifactDefinition artifactMD) { + Either<Boolean, ResponseFormat> result = Either.left(true); + Either<ESArtifactData, CassandraOperationStatus> eitherArtifactData = artifactCassandraDao.getArtifact(artifactMD.getEsId()); + // Either<ESArtifactData, ResourceUploadStatus> eitherArtifactData = + // esCatalogDao.getArtifact(artifactMD.getEsId()); + if (eitherArtifactData.isLeft()) { + byte[] data = eitherArtifactData.left().value().getDataAsArray(); + if (!GeneralUtility.isBase64Encoded(data)) { + data = Base64.encodeBase64(data); + } + payloadWrapper.setInnerElement(data); + } else { + StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(eitherArtifactData.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus)); + result = Either.right(responseFormat); + } + return result; + + } + + @SuppressWarnings("unchecked") + private void validateEnvVsHeat(Wrapper<ResponseFormat> errorWrapper, ArtifactDefinition envArtifact, ArtifactDefinition heatArtifact, byte[] heatPayloadData) { + + String envPayload = (GeneralUtility.isBase64Encoded(envArtifact.getPayloadData())) ? new String(Base64.decodeBase64(envArtifact.getPayloadData())) : new String(envArtifact.getPayloadData()); + Map<String, Object> heatEnvToscaJson = (Map<String, Object>) new Yaml().load(envPayload); + + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(heatPayloadData)) ? new String(Base64.decodeBase64(heatPayloadData)) : new String(heatPayloadData); + Map<String, Object> heatToscaJson = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + + Either<Map<String, Object>, ResultStatusEnum> eitherHeatEnvProperties = ImportUtils.findFirstToscaMapElement(heatEnvToscaJson, ToscaTagNamesEnum.PARAMETERS); + Either<Map<String, Object>, ResultStatusEnum> eitherHeatProperties = ImportUtils.findFirstToscaMapElement(heatToscaJson, ToscaTagNamesEnum.PARAMETERS); + if (eitherHeatEnvProperties.isRight()) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.CORRUPTED_FORMAT, "Heat Env"); + errorWrapper.setInnerElement(responseFormat); + log.debug("Invalid heat env format for file:{}", envArtifact.getArtifactName()); + } else if (eitherHeatProperties.isRight()) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.MISMATCH_HEAT_VS_HEAT_ENV, envArtifact.getArtifactName(), heatArtifact.getArtifactName()); + errorWrapper.setInnerElement(responseFormat); + log.debug("Validation of heat_env for artifact:{} vs heat artifact for artifact :{} failed", envArtifact.getArtifactName(), heatArtifact.getArtifactName()); + } else { + Set<String> heatPropertiesKeys = eitherHeatProperties.left().value().keySet(); + Set<String> heatEnvPropertiesKeys = eitherHeatEnvProperties.left().value().keySet(); + heatEnvPropertiesKeys.removeAll(heatPropertiesKeys); + if (heatEnvPropertiesKeys.size() > 0) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.MISMATCH_HEAT_VS_HEAT_ENV, envArtifact.getArtifactName(), heatArtifact.getArtifactName()); + errorWrapper.setInnerElement(responseFormat); + } + } + } + + private void validateValidYaml(Wrapper<ResponseFormat> errorWrapper, ArtifactDefinition artifactInfo) { + YamlToObjectConverter yamlConvertor = new YamlToObjectConverter(); + boolean isYamlValid = yamlConvertor.isValidYaml(artifactInfo.getPayloadData()); + if (!isYamlValid) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.INVALID_YAML, artifactInfo.getArtifactType()); + errorWrapper.setInnerElement(responseFormat); + log.debug("Yaml is not valid for artifact : {}", artifactInfo.getArtifactName()); + } + } + + public boolean isValidXml(byte[] xmlToParse) { + XMLReader parser = new SAXParser(); + boolean isXmlValid = true; + try { + parser.parse(new InputSource(new ByteArrayInputStream(xmlToParse))); + } catch (IOException | SAXException e) { + isXmlValid = false; + } + return isXmlValid; + } + + public boolean isValidJson(byte[] jsonToParse) { + String parsed = new String(jsonToParse); + try { + gson.fromJson(parsed, Object.class); + } catch (Exception e) { + return false; + } + return true; + } + + public void validateSingleArtifactType(Wrapper<ResponseFormat> errorWrapper, ArtifactTypeEnum allowedArtifactType, Component parentComponent, NodeTypeEnum parentType, String parentRiId) { + boolean typeArtifactFound = false; + // Iterator<ArtifactDefinition> parentDeploymentArtifactsItr = + // (parentType == NodeTypeEnum.Resource) ? + // informationDeployedArtifactsBusinessLogic.getAllDeployableArtifacts((Resource) + // parentComponent).iterator() + // : getDeploymentArtifacts(parentComponent, parentType).iterator(); + + Iterator<ArtifactDefinition> parentDeploymentArtifactsItr = getDeploymentArtifacts(parentComponent, parentType, parentRiId).iterator(); + + while (!typeArtifactFound && parentDeploymentArtifactsItr.hasNext()) { + ArtifactTypeEnum foundArtifactType = ArtifactTypeEnum.findType(parentDeploymentArtifactsItr.next().getArtifactType()); + typeArtifactFound = (foundArtifactType == allowedArtifactType); + } + if (typeArtifactFound) { + String parentName = parentComponent.getName(); + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS, parentType.name(), parentName, allowedArtifactType.getType(), allowedArtifactType.getType()); + + errorWrapper.setInnerElement(responseFormat); + log.debug("Can't upload artifact of type: {}, because another artifact of this type already exist.", allowedArtifactType.getType()); + + } + } + + public void validateSingleDeploymentArtifactName(Wrapper<ResponseFormat> errorWrapper, String artifactName, Component parentComponent, NodeTypeEnum parentType) { + boolean artifactNameFound = false; + // Iterator<ArtifactDefinition> parentDeploymentArtifactsItr = + // (parentType == NodeTypeEnum.Resource) ? + // informationDeployedArtifactsBusinessLogic.getAllDeployableArtifacts((Resource) + // parentComponent).iterator() + // : getDeploymentArtifacts(parentComponent, parentType).iterator(); + + Iterator<ArtifactDefinition> parentDeploymentArtifactsItr = getDeploymentArtifacts(parentComponent, parentType, null).iterator(); + + while (!artifactNameFound && parentDeploymentArtifactsItr.hasNext()) { + artifactNameFound = (artifactName.equalsIgnoreCase(parentDeploymentArtifactsItr.next().getArtifactName())); + } + if (artifactNameFound) { + String parentName = parentComponent.getName(); + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS, parentType.name(), parentName, artifactName); + + errorWrapper.setInnerElement(responseFormat); + log.debug("Can't upload artifact: {}, because another artifact with this name already exist.", artifactName); + + } + } + + private void validateHeatExist(String heatEnvId, Wrapper<ResponseFormat> errorWrapper, Wrapper<ArtifactDefinition> heatArtifactMDWrapper, Collection<ArtifactDefinition> parentDeploymentArtifacts) { + boolean heatFound = false; + Either<ArtifactDefinition, StorageOperationStatus> res = artifactOperation.getHeatArtifactByHeatEnvId(heatEnvId, true); + if (res.isRight()) { + return; + } + ArtifactDefinition heatArtifact = res.left().value(); + Iterator<ArtifactDefinition> parentArtifactsItr = parentDeploymentArtifacts.iterator(); + while (!heatFound && parentArtifactsItr.hasNext()) { + ArtifactDefinition currArtifact = parentArtifactsItr.next(); + if (heatArtifact.getUniqueId().equals(currArtifact.getUniqueId())) { + heatFound = true; + heatArtifactMDWrapper.setInnerElement(currArtifact); + log.trace("In validateHeatExist found artifact {}", currArtifact); + /* + * ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(currArtifact.getArtifactType()); if(artifactType == ArtifactTypeEnum.HEAT || artifactType == ArtifactTypeEnum.HEAT_VOL || artifactType == ArtifactTypeEnum.HEAT_NET){ + * heatFound = true; } if (heatFound) { heatArtifactMDWrapper.setInnerElement(currArtifact); } + */ + } + } + if (!heatFound) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.MISSING_HEAT); + errorWrapper.setInnerElement(responseFormat); + log.debug("Can't create heat env artifact because No heat Artifact exist."); + } + + } + + private Either<Boolean, ResponseFormat> validateHeatDeploymentArtifact(Component parentComponent, String userId, boolean isCreate, ArtifactDefinition artifactInfo, ArtifactDefinition currentArtifact, NodeTypeEnum parentType) { + log.trace("Started HEAT pre-payload validation for artifact {}", artifactInfo.getArtifactLabel()); + // timeout > 0 for HEAT artifacts + Integer timeout = artifactInfo.getTimeout(); + Integer defaultTimeout = (isCreate) ? defaultHeatTimeout : currentArtifact.getTimeout(); + if (timeout == null) { + artifactInfo.setTimeout(defaultTimeout); + // HEAT artifact but timeout is invalid + } else if (timeout < 1) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_INVALID_TIMEOUT)); + } + + // US649856 - Allow several HEAT files on Resource + /* + * if (isCreate) { Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); validateSingleArtifactType(errorWrapper, ArtifactTypeEnum.findType(artifactInfo.getArtifactType()), parentComponent, parentType); if (!errorWrapper.isEmpty()) { return + * Either.right(errorWrapper.getInnerElement()); } } + */ + + log.trace("Ended HEAT validation for artifact {}", artifactInfo.getArtifactLabel()); + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateResourceType(ResourceTypeEnum resourceType, ArtifactDefinition artifactInfo, List<String> typeList) { + String listToString = (typeList != null) ? typeList.toString() : ""; + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE, artifactInfo.getArtifactName(), listToString, resourceType.getValue()); + Either<Boolean, ResponseFormat> either = Either.right(responseFormat); + String resourceTypeName = resourceType.name(); + if (typeList != null && typeList.contains(resourceTypeName)) { + either = Either.left(true); + } + return either; + } + + private Either<ArtifactDefinition, ResponseFormat> validateAndConvertHeatParamers(ArtifactDefinition artifactInfo, String artifactType) { + if (artifactInfo.getHeatParameters() != null) { + for (HeatParameterDefinition heatParam : artifactInfo.getHeatParameters()) { + String parameterType = heatParam.getType(); + HeatParameterType heatParameterType = HeatParameterType.isValidType(parameterType); + String artifactTypeStr = artifactType != null ? artifactType : ArtifactTypeEnum.HEAT.getType(); + if (heatParameterType == null) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_HEAT_PARAMETER_TYPE, artifactTypeStr, heatParam.getType()); + return Either.right(responseFormat); + } + + StorageOperationStatus validateAndUpdateProperty = heatParametersOperation.validateAndUpdateProperty(heatParam); + if (validateAndUpdateProperty != StorageOperationStatus.OK) { + log.debug("Heat parameter {} is invalid. Status is: {}", heatParam.getName(), validateAndUpdateProperty); + ActionStatus status = ActionStatus.INVALID_HEAT_PARAMETER_VALUE; + ResponseFormat responseFormat = componentsUtils.getResponseFormat(status, artifactTypeStr, heatParam.getType(), heatParam.getName()); + return Either.right(responseFormat); + } + } + } + return Either.left(artifactInfo); + } + + public List<ArtifactDefinition> getDeploymentArtifacts(Component parentComponent, NodeTypeEnum parentType, String ciId) { + List<ArtifactDefinition> deploymentArtifacts = new ArrayList<>(); + if (parentComponent.getDeploymentArtifacts() != null && ciId != null) { + if (NodeTypeEnum.ResourceInstance == parentType) { + Either<ComponentInstance, ResponseFormat> getRI = getRIFromComponent(parentComponent, ciId, null, null, null); + if (getRI.isRight()) { + return deploymentArtifacts; + } + ComponentInstance ri = getRI.left().value(); + deploymentArtifacts.addAll(ri.getDeploymentArtifacts().values()); + } else { + deploymentArtifacts.addAll(parentComponent.getDeploymentArtifacts().values()); + } + } + return deploymentArtifacts; + } + + private void checkCreateFields(User user, ArtifactDefinition artifactInfo, ArtifactGroupTypeEnum type) { + // on create if null add informational to current + if (artifactInfo.getArtifactGroupType() == null) { + artifactInfo.setArtifactGroupType(type); + } + if (artifactInfo.getUniqueId() != null) { + log.error("artifact uniqid cannot be set ignoring"); + } + artifactInfo.setUniqueId(null); + + if (artifactInfo.getArtifactRef() != null) { + log.error("artifact ref cannot be set ignoring"); + } + artifactInfo.setArtifactRef(null); + + if (artifactInfo.getArtifactRepository() != null) { + log.error("artifact repository cannot be set ignoring"); + } + artifactInfo.setArtifactRepository(null); + + if (artifactInfo.getUserIdCreator() != null) { + log.error("creator uuid cannot be set ignoring"); + } + artifactInfo.setArtifactCreator(user.getUserId()); + + if (artifactInfo.getUserIdLastUpdater() != null) { + log.error("userId of last updater cannot be set ignoring"); + } + artifactInfo.setUserIdLastUpdater(user.getUserId()); + + if (artifactInfo.getCreatorFullName() != null) { + log.error("creator Full name cannot be set ignoring"); + } + String fullName = user.getFirstName() + " " + user.getLastName(); + artifactInfo.setUpdaterFullName(fullName); + + if (artifactInfo.getUpdaterFullName() != null) { + log.error("updater Full name cannot be set ignoring"); + } + artifactInfo.setUpdaterFullName(fullName); + + if (artifactInfo.getCreationDate() != null) { + log.error("Creation Date cannot be set ignoring"); + } + long time = System.currentTimeMillis(); + artifactInfo.setCreationDate(time); + + if (artifactInfo.getLastUpdateDate() != null) { + log.error("Last Update Date cannot be set ignoring"); + } + artifactInfo.setLastUpdateDate(time); + + if (artifactInfo.getEsId() != null) { + log.error("es id cannot be set ignoring"); + } + artifactInfo.setEsId(null); + + } + + private Either<ArtifactDefinition, ResponseFormat> fetchCurrentArtifact(boolean isCreate, String artifactId) { + Either<ArtifactDefinition, StorageOperationStatus> artifactById = artifactOperation.getArtifactById(artifactId, true); + if (isCreate == false && artifactById.isRight()) { + // in case of update artifact must be + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeArtifactMissingError, "Artifact Update / Upload", artifactId); + BeEcompErrorManager.getInstance().logBeArtifactMissingError("Artifact Update / Upload", artifactId); + log.debug("Failed to fetch artifact {}. error: {}", artifactId, artifactById.right().value()); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(artifactById.right().value()), artifactId)); + } + if (isCreate && artifactById.isLeft()) { + log.debug("Artifact {} already exist", artifactId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_EXIST, artifactById.left().value().getArtifactLabel())); + } + ArtifactDefinition currentArtifactInfo = null; + if (artifactById.isLeft()) { + // get previous value + currentArtifactInfo = artifactById.left().value(); + } + return Either.left(currentArtifactInfo); + } + + private Either<ActionStatus, ResponseFormat> handleArtifactLabel(String resourceId, boolean isCreate, String artifactId, ArtifactDefinition artifactInfo, String interfaceName, String operationName, ArtifactDefinition currentArtifactInfo, + NodeTypeEnum parentType) { + String artifactLabel = artifactInfo.getArtifactLabel(); + + if (operationName == null && (artifactInfo.getArtifactLabel() == null || artifactInfo.getArtifactLabel().isEmpty())) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingArtifactInformationError, "Artifact Update / Upload", "artifactLabel"); + BeEcompErrorManager.getInstance().logBeMissingArtifactInformationError("Artifact Update / Upload", "artifactLabel"); + log.debug("missing artifact logical name for component {}", resourceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_LABEL)); + } + if (isCreate && !artifactInfo.getMandatory()) { + + if (operationName != null) { + if (artifactInfo.getArtifactLabel() != null && !operationName.equals(artifactInfo.getArtifactLabel())) { + log.debug("artifact label cannot be set {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED)); + } else { + artifactLabel = operationName; + } + } + String displayName = ValidationUtils.cleanArtifactDisplayName(artifactLabel); + artifactInfo.setArtifactDisplayName(displayName); + + if (!ValidationUtils.validateArtifactLabel(artifactLabel)) { + log.debug("Invalid format form Artifact label : {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + artifactLabel = ValidationUtils.normalizeArtifactLabel(artifactLabel); + + if (artifactLabel.isEmpty()) { + log.debug("missing normalized artifact logical name for component {}", resourceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_LABEL)); + } + + if (!ValidationUtils.validateArtifactLabelLength(artifactLabel)) { + log.debug("Invalid lenght form Artifact label : {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, ARTIFACT_LABEL, String.valueOf(ValidationUtils.ARTIFACT_LABEL_LENGTH))); + } + if (!validateLabelUniqueness(resourceId, artifactLabel, parentType)) { + log.debug("Non unique Artifact label : {}", artifactLabel); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_EXIST, artifactLabel)); + } + } + artifactInfo.setArtifactLabel(artifactLabel); + + if (currentArtifactInfo != null && !currentArtifactInfo.getArtifactLabel().equals(artifactInfo.getArtifactLabel())) { + log.info("Logical artifact's name cannot be changed {}", artifactId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED)); + } + return Either.left(ActionStatus.OK); + } + + private boolean validateLabelUniqueness(String parentId, String artifactLabel, NodeTypeEnum parentType) { + boolean isUnique = true; + Either<Map<String, ArtifactDefinition>, StorageOperationStatus> artifacts = artifactOperation.getArtifacts(parentId, parentType, true); + if (artifacts.isLeft()) { + for (String label : artifacts.left().value().keySet()) { + if (label.equals(artifactLabel)) { + isUnique = false; + break; + } + } + } + if (parentType.equals(NodeTypeEnum.Resource)) { + Either<Map<String, InterfaceDefinition>, StorageOperationStatus> allInterfacesOfResource = interfaceLifecycleOperation.getAllInterfacesOfResource(parentId, true); + if (allInterfacesOfResource.isLeft()) { + for (InterfaceDefinition interace : allInterfacesOfResource.left().value().values()) { + for (Operation operation : interace.getOperations().values()) { + if (operation.getImplementation() != null && operation.getImplementation().getArtifactLabel().equals(artifactLabel)) { + isUnique = false; + break; + } + } + } + } + } + return isUnique; + } + + private String composeArtifactId(String resourceId, String artifactId, ArtifactDefinition artifactInfo, String interfaceName, String operationName) { + String id = artifactId; + if (artifactId == null || artifactId.isEmpty()) { + String uniqueId = null; + if (interfaceName != null && operationName != null) { + uniqueId = UniqueIdBuilder.buildArtifactByInterfaceUniqueId(resourceId, interfaceName, operationName, artifactInfo.getArtifactLabel()); + } else { + uniqueId = UniqueIdBuilder.buildPropertyUniqueId(resourceId, artifactInfo.getArtifactLabel()); + } + artifactInfo.setUniqueId(uniqueId); + artifactInfo.setEsId(uniqueId); + id = uniqueId; + } else { + artifactInfo.setUniqueId(artifactId); + artifactInfo.setEsId(artifactId); + } + return id; + } + + private Either<ActionStatus, ResponseFormat> validateArtifactType(String userId, ArtifactDefinition artifactInfo, NodeTypeEnum parentType) { + if (artifactInfo.getArtifactType() == null || artifactInfo.getArtifactType().isEmpty()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeMissingArtifactInformationError, "Artifact Upload / Update"); + BeEcompErrorManager.getInstance().logBeMissingArtifactInformationError("Artifact Update / Upload", "artifactLabel"); + log.debug("Missing artifact type for artifact {}", artifactInfo.getArtifactName()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_ARTIFACT_TYPE)); + } + + boolean artifactTypeExist = false; + Either<List<ArtifactType>, ActionStatus> allArtifactTypes = null; + ArtifactGroupTypeEnum artifactGroupType = artifactInfo.getArtifactGroupType(); + + if ((artifactGroupType != null) && artifactGroupType.equals(ArtifactGroupTypeEnum.DEPLOYMENT)) { + allArtifactTypes = getDeploymentArtifactTypes(userId, artifactInfo, parentType); + } else { + + allArtifactTypes = elementOperation.getAllArtifactTypes(); + } + if (allArtifactTypes.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidConfigurationError, "Artifact Upload / Update", "artifactTypes", allArtifactTypes.right().value().name()); + BeEcompErrorManager.getInstance().logBeInvalidConfigurationError("Artifact Upload / Update", "artifactTypes", allArtifactTypes.right().value().name()); + log.debug("Failed to retrieve list of suported artifact types. error: {}", allArtifactTypes.right().value()); + return Either.right(componentsUtils.getResponseFormatByUserId(allArtifactTypes.right().value(), userId)); + } + + for (ArtifactType type : allArtifactTypes.left().value()) { + if (type.getName().equalsIgnoreCase(artifactInfo.getArtifactType())) { + artifactInfo.setArtifactType(artifactInfo.getArtifactType().toUpperCase()); + artifactTypeExist = true; + break; + } + } + + if (!artifactTypeExist) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidTypeError, "Artifact Upload / Delete / Update - Not supported artifact type", artifactInfo.getArtifactType(), "Artifact " + artifactInfo.getArtifactName()); + BeEcompErrorManager.getInstance().logBeInvalidTypeError("Artifact Upload / Delete / Update - Not supported artifact type", artifactInfo.getArtifactType(), "Artifact " + artifactInfo.getArtifactName()); + log.debug("Not supported artifact type = {}", artifactInfo.getArtifactType()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED, artifactInfo.getArtifactType())); + } + + return Either.left(ActionStatus.OK); + } + + private Either<List<ArtifactType>, ActionStatus> getDeploymentArtifactTypes(String userId, ArtifactDefinition artifactInfo, NodeTypeEnum parentType) { + + Map<String, DeploymentArtifactTypeConfig> deploymentArtifacts = null; + List<ArtifactType> artifactTypes = new ArrayList<ArtifactType>(); + + if (parentType.equals(NodeTypeEnum.Service)) { + deploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getServiceDeploymentArtifacts(); + } else if (parentType.equals(NodeTypeEnum.ResourceInstance)) { + deploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceInstanceDeploymentArtifacts(); + } else { + deploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceDeploymentArtifacts(); + } + if (deploymentArtifacts != null) { + for (String artifactType : deploymentArtifacts.keySet()) { + ArtifactType artifactT = new ArtifactType(); + artifactT.setName(artifactType); + artifactTypes.add(artifactT); + } + return Either.left(artifactTypes); + } else { + return Either.right(ActionStatus.GENERAL_ERROR); + } + + } + + private Either<Boolean, ResponseFormat> validateFirstUpdateHasPayload(ArtifactDefinition artifactInfo, ArtifactDefinition currentArtifact) { + if (currentArtifact.getEsId() == null && (artifactInfo.getPayloadData() == null || artifactInfo.getPayloadData().length == 0)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_PAYLOAD)); + } + return Either.left(true); + + } + + private Either<Boolean, ResponseFormat> validateAndSetArtifactname(ArtifactDefinition artifactInfo) { + if (artifactInfo.getArtifactName() == null || artifactInfo.getArtifactName().isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_ARTIFACT_NAME)); + } + + String normalizeFileName = ValidationUtils.normalizeFileName(artifactInfo.getArtifactName()); + if (normalizeFileName == null || normalizeFileName.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_ARTIFACT_NAME)); + } + artifactInfo.setArtifactName(normalizeFileName); + + if (!ValidationUtils.validateArtifactNameLength(artifactInfo.getArtifactName())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, ARTIFACT_NAME, String.valueOf(ValidationUtils.ARTIFACT_NAME_LENGTH))); + } + + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateArtifactTypeNotChanged(ArtifactDefinition artifactInfo, ArtifactDefinition currentArtifact) { + if (artifactInfo.getArtifactType() == null || artifactInfo.getArtifactType().isEmpty()) { + log.info("artifact type is missing operation ignored"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_ARTIFACT_TYPE)); + } + + if (!currentArtifact.getArtifactType().equalsIgnoreCase(artifactInfo.getArtifactType())) { + log.info("artifact type cannot be changed operation ignored"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + return Either.left(true); + } + + private Either<ArtifactDefinition, ResponseFormat> validateOrSetArtifactGroupType(ArtifactDefinition artifactInfo, ArtifactDefinition currentArtifact) { + if (artifactInfo.getArtifactGroupType() == null) { + artifactInfo.setArtifactGroupType(currentArtifact.getArtifactGroupType()); + } + + else if (!currentArtifact.getArtifactGroupType().getType().equalsIgnoreCase(artifactInfo.getArtifactGroupType().getType())) { + log.info("artifact group type cannot be changed. operation failed"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + return Either.left(artifactInfo); + } + + private void checkAndSetUnUpdatableFields(User user, ArtifactDefinition artifactInfo, ArtifactDefinition currentArtifact, ArtifactGroupTypeEnum type) { + + // on update if null add informational to current + if (currentArtifact.getArtifactGroupType() == null && type != null) { + currentArtifact.setArtifactGroupType(type); + } + + if (artifactInfo.getUniqueId() != null && !currentArtifact.getUniqueId().equals(artifactInfo.getUniqueId())) { + log.error("artifact uniqid cannot be set ignoring"); + } + artifactInfo.setUniqueId(currentArtifact.getUniqueId()); + + if (artifactInfo.getArtifactRef() != null && !currentArtifact.getArtifactRef().equals(artifactInfo.getArtifactRef())) { + log.error("artifact ref cannot be set ignoring"); + } + artifactInfo.setArtifactRef(currentArtifact.getArtifactRef()); + + if (artifactInfo.getArtifactRepository() != null && !currentArtifact.getArtifactRepository().equals(artifactInfo.getArtifactRepository())) { + log.error("artifact repository cannot be set ignoring"); + } + artifactInfo.setArtifactRepository(currentArtifact.getArtifactRepository()); + + if (artifactInfo.getUserIdCreator() != null && !currentArtifact.getUserIdCreator().equals(artifactInfo.getUserIdCreator())) { + log.error("creator uuid cannot be set ignoring"); + } + artifactInfo.setUserIdCreator(currentArtifact.getUserIdCreator()); + + if (artifactInfo.getArtifactCreator() != null && !currentArtifact.getArtifactCreator().equals(artifactInfo.getArtifactCreator())) { + log.error("artifact creator cannot be set ignoring"); + } + artifactInfo.setArtifactCreator(currentArtifact.getArtifactCreator()); + + if (artifactInfo.getUserIdLastUpdater() != null && !currentArtifact.getUserIdLastUpdater().equals(artifactInfo.getUserIdLastUpdater())) { + log.error("userId of last updater cannot be set ignoring"); + } + artifactInfo.setUserIdLastUpdater(user.getUserId()); + + if (artifactInfo.getCreatorFullName() != null && !currentArtifact.getCreatorFullName().equals(artifactInfo.getCreatorFullName())) { + log.error("creator Full name cannot be set ignoring"); + } + artifactInfo.setCreatorFullName(currentArtifact.getCreatorFullName()); + + if (artifactInfo.getUpdaterFullName() != null && !currentArtifact.getUpdaterFullName().equals(artifactInfo.getUpdaterFullName())) { + log.error("updater Full name cannot be set ignoring"); + } + String fullName = user.getFirstName() + " " + user.getLastName(); + artifactInfo.setUpdaterFullName(fullName); + + if (artifactInfo.getCreationDate() != null && !currentArtifact.getCreationDate().equals(artifactInfo.getCreationDate())) { + log.error("Creation Date cannot be set ignoring"); + } + artifactInfo.setCreationDate(currentArtifact.getCreationDate()); + + if (artifactInfo.getLastUpdateDate() != null && !currentArtifact.getLastUpdateDate().equals(artifactInfo.getLastUpdateDate())) { + log.error("Last Update Date cannot be set ignoring"); + } + long time = System.currentTimeMillis(); + artifactInfo.setLastUpdateDate(time); + + if (artifactInfo.getEsId() != null && !currentArtifact.getEsId().equals(artifactInfo.getEsId())) { + log.error("es id cannot be set ignoring"); + } + artifactInfo.setEsId(currentArtifact.getUniqueId()); + + if (artifactInfo.getArtifactDisplayName() != null && !currentArtifact.getArtifactDisplayName().equals(artifactInfo.getArtifactDisplayName())) { + log.error(" Artifact Display Name cannot be set ignoring"); + } + artifactInfo.setArtifactDisplayName(currentArtifact.getArtifactDisplayName()); + + if (artifactInfo.getServiceApi() != null && !currentArtifact.getServiceApi().equals(artifactInfo.getServiceApi())) { + log.debug("serviceApi cannot be set. ignoring."); + } + artifactInfo.setServiceApi(currentArtifact.getServiceApi()); + + if (artifactInfo.getArtifactGroupType() != null && !currentArtifact.getArtifactGroupType().equals(artifactInfo.getArtifactGroupType())) { + log.debug("artifact group cannot be set. ignoring."); + } + artifactInfo.setArtifactGroupType(currentArtifact.getArtifactGroupType()); + + artifactInfo.setArtifactVersion(currentArtifact.getArtifactVersion()); + + if (artifactInfo.getArtifactUUID() != null && !artifactInfo.getArtifactUUID().isEmpty() && !currentArtifact.getArtifactUUID().equals(artifactInfo.getArtifactUUID())) { + log.debug("artifact UUID cannot be set. ignoring."); + } + artifactInfo.setArtifactUUID(currentArtifact.getArtifactUUID()); + + if ((artifactInfo.getHeatParameters() != null) && (currentArtifact.getHeatParameters() != null) && !artifactInfo.getHeatParameters().isEmpty() && !currentArtifact.getHeatParameters().isEmpty()) { + checkAndSetUnupdatableHeatParams(artifactInfo.getHeatParameters(), currentArtifact.getHeatParameters()); + } + } + + private void checkAndSetUnupdatableHeatParams(List<HeatParameterDefinition> heatParameters, List<HeatParameterDefinition> currentParameters) { + + Map<String, HeatParameterDefinition> currentParametersMap = getMapOfParameters(currentParameters); + for (HeatParameterDefinition parameter : heatParameters) { + HeatParameterDefinition currentParam = currentParametersMap.get(parameter.getUniqueId()); + + if (currentParam != null) { + + if (parameter.getName() != null && !parameter.getName().equalsIgnoreCase(currentParam.getName())) { + log.debug("heat parameter name cannot be updated ({}). ignoring.", parameter.getName()); + parameter.setName(currentParam.getName()); + } + if (parameter.getDefaultValue() != null && !parameter.getDefaultValue().equalsIgnoreCase(currentParam.getDefaultValue())) { + log.debug("heat parameter defaultValue cannot be updated ({}). ignoring.", parameter.getDefaultValue()); + parameter.setDefaultValue(currentParam.getDefaultValue()); + } + if (parameter.getType() != null && !parameter.getType().equalsIgnoreCase(currentParam.getType())) { + log.debug("heat parameter type cannot be updated ({}). ignoring.", parameter.getType()); + parameter.setType(currentParam.getType()); + } + if (parameter.getDescription() != null && !parameter.getDescription().equalsIgnoreCase(currentParam.getDescription())) { + log.debug("heat parameter description cannot be updated ({}). ignoring.", parameter.getDescription()); + parameter.setDescription(currentParam.getDescription()); + } + + // check and set current value + if ((parameter.getCurrentValue() == null) && (currentParam.getDefaultValue() != null)) { + log.debug("heat parameter current value is null. set it to default value {}). ignoring.", parameter.getDefaultValue()); + parameter.setCurrentValue(currentParam.getDefaultValue()); + } + } + } + } + + private Map<String, HeatParameterDefinition> getMapOfParameters(List<HeatParameterDefinition> currentParameters) { + + Map<String, HeatParameterDefinition> currentParamsMap = new HashMap<String, HeatParameterDefinition>(); + for (HeatParameterDefinition param : currentParameters) { + currentParamsMap.put(param.getUniqueId(), param); + } + return currentParamsMap; + } + + private Either<Boolean, ResponseFormat> validateAndServiceApiUrl(ArtifactDefinition artifactInfo) { + if (!ValidationUtils.validateStringNotEmpty(artifactInfo.getApiUrl())) { + log.debug("Artifact url cannot be empty."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_URL)); + } + artifactInfo.setApiUrl(artifactInfo.getApiUrl().toLowerCase()); + + if (!ValidationUtils.validateUrl(artifactInfo.getApiUrl())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_SERVICE_API_URL)); + } + if (!ValidationUtils.validateUrlLength(artifactInfo.getApiUrl())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, ARTIFACT_URL, String.valueOf(ValidationUtils.API_URL_LENGTH))); + } + + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndCleanDescription(ArtifactDefinition artifactInfo) { + if (artifactInfo.getDescription() == null || artifactInfo.getDescription().isEmpty()) { + log.debug("Artifact description cannot be empty."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_DESCRIPTION)); + } + String description = artifactInfo.getDescription(); + description = ValidationUtils.removeNoneUtf8Chars(description); + description = ValidationUtils.normaliseWhitespace(description); + description = ValidationUtils.stripOctets(description); + description = ValidationUtils.removeHtmlTagsOnly(description); + if (!ValidationUtils.validateIsEnglish(description)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + if (!ValidationUtils.validateLength(description, ValidationUtils.ARTIFACT_DESCRIPTION_MAX_LENGTH)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, ARTIFACT_DESCRIPTION, String.valueOf(ValidationUtils.ARTIFACT_DESCRIPTION_MAX_LENGTH))); + } + artifactInfo.setDescription(description); + return Either.left(true); + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> updateArtifactFlow(org.openecomp.sdc.be.model.Component parent, String parentId, String artifactId, ArtifactDefinition artifactInfo, User user, byte[] decodedPayload, + ComponentTypeEnum componentType, AuditingActionEnum auditingAction, String interfaceType, String operationName) { + ESArtifactData artifactData = createEsArtifactData(artifactInfo, decodedPayload); + String prevArtifactId = null; + String currArtifactId = artifactId; + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + Either<ArtifactDefinition, Operation> insideEither = null; + + if (artifactData == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Update Artifact"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Update Artifact"); + log.debug("Failed to create artifact object for ES."); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + resultOp = Either.right(responseFormat); + return resultOp; + } + log.debug("Try to update entry on graph"); + String artifactUniqueId = null; + ArtifactDefinition artifactDefinition = null; + StorageOperationStatus error = null; + + boolean isLeft = false; + if (interfaceType != null && operationName != null) { + // lifecycle artifact + Operation operation = convertToOperation(artifactInfo, operationName); + + Either<Operation, StorageOperationStatus> result = interfaceLifecycleOperation.updateInterfaceOperation(parentId, interfaceType, operationName, operation); + + isLeft = result.isLeft(); + if (isLeft) { + artifactUniqueId = result.left().value().getUniqueId(); + artifactDefinition = result.left().value().getImplementation(); + + insideEither = Either.right(result.left().value()); + resultOp = Either.left(insideEither); + } else { + error = result.right().value(); + } + } else { + + NodeTypeEnum convertParentType = convertParentType(componentType); + Either<ArtifactDefinition, StorageOperationStatus> result = artifactOperation.updateArifactOnResource(artifactInfo, parentId, artifactId, convertParentType, true); + isLeft = result.isLeft(); + if (isLeft) { + artifactUniqueId = result.left().value().getUniqueId(); + artifactDefinition = result.left().value(); + + insideEither = Either.left(result.left().value()); + resultOp = Either.left(insideEither); + } else { + error = result.right().value(); + } + } + if (isLeft) { + log.debug("Enty on graph is updated. Update artifact in ES"); + boolean res; + // Changing previous and current artifactId for auditing + prevArtifactId = currArtifactId; + currArtifactId = artifactDefinition.getUniqueId(); + + if (!artifactDefinition.getUniqueId().equals(artifactId)) { + // different ids ==> artifact node was cloned . + // if no data in request get from ES + if (decodedPayload == null) { + if (!artifactDefinition.getMandatory() || artifactDefinition.getEsId() != null) { + Either<ESArtifactData, CassandraOperationStatus> artifactFromCassandra = artifactCassandraDao.getArtifact(artifactId); + // Either<ESArtifactData, ResourceUploadStatus> + // artifactfromES = daoUploader.getArtifact(artifactId); + if (artifactFromCassandra.isRight()) { + log.debug("Failed to get artifact data from ES for artifact id {}", artifactId); + StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(artifactFromCassandra.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus)); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + resultOp = Either.right(responseFormat); + return resultOp; + } + // clone data to new artifact + artifactData.setData(artifactFromCassandra.left().value().getData()); + } + } + artifactData.setId(artifactDefinition.getUniqueId()); + // create new entry in ES + res = true; + if (artifactData.getData() != null) { + res = saveArtifacts(artifactData, parentId, false); + // set on graph object id of artifact in ES! + if (res) { + artifactInfo.setEsId(artifactData.getId()); + Either<ArtifactDefinition, StorageOperationStatus> updateArifactRes = artifactOperation.updateArifactDefinition(artifactInfo, true); + if (updateArifactRes.isRight()) { + log.debug("Failed to update artifact on graph - {}", artifactId); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateArifactRes.right().value())); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + resultOp = Either.right(responseFormat); + return resultOp; + + } else { + insideEither = Either.left(updateArifactRes.left().value()); + resultOp = Either.left(insideEither); + } + } + } + } else { + res = true; + if (artifactData.getData() != null) { + // override artifact in ES + res = saveArtifacts(artifactData, parentId, true); + if (res && artifactDefinition.getMandatory()) { + artifactInfo.setEsId(artifactData.getId()); + Either<ArtifactDefinition, StorageOperationStatus> updateArifactRes = artifactOperation.updateArifactDefinition(artifactInfo, true); + if (updateArifactRes.isRight()) { + log.debug("Failed to update artifact on graph - {}", artifactId); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(updateArifactRes.right().value()), artifactId); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + resultOp = Either.right(responseFormat); + return resultOp; + + } + } + } + } + if (res) { + log.debug("Artifact saved into ES - {}", artifactUniqueId); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + // resultOp = Either.left(result.left().value()); + // return resultOp; + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Update Artifact"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Update Artifact"); + log.debug("Failed to save the artifact."); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + resultOp = Either.right(responseFormat); + // return resultOp; + } + } else { + log.debug("Failed to create entry on graph for artifact {}", artifactInfo.getArtifactDisplayName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(error), artifactInfo.getArtifactDisplayName()); + handleAuditing(auditingAction, parent, parentId, user, artifactInfo, prevArtifactId, currArtifactId, responseFormat, componentType, null); + resultOp = Either.right(responseFormat); + // return resultOp; + } + + return resultOp; + } + + private Either<byte[], ResponseFormat> handlePayload(ArtifactDefinition artifactInfo, boolean isArtifactMetadataUpdate) { + log.trace("Starting payload handling"); + byte[] payload = artifactInfo.getPayloadData(); + byte[] decodedPayload = null; + + if (payload != null && payload.length != 0) { + + decodedPayload = Base64.decodeBase64(payload); + if (decodedPayload.length == 0) { + log.debug("Failed to decode the payload."); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + return Either.right(responseFormat); + } + + String checkSum = GeneralUtility.calculateMD5ByByteArray(decodedPayload); + artifactInfo.setArtifactChecksum(checkSum); + log.trace("Calculated checksum, base64 payload: {}, checksum: {}", payload, checkSum); + + // Specific payload validations of different types + Either<Boolean, ResponseFormat> isValidPayload = Either.left(true); + if (isDeploymentArtifact(artifactInfo)) { + log.trace("Starting deployment artifacts payload validation"); + String artifactType = artifactInfo.getArtifactType(); + if (ArtifactTypeEnum.HEAT.getType().equalsIgnoreCase(artifactType) || ArtifactTypeEnum.HEAT_VOL.getType().equalsIgnoreCase(artifactType) || ArtifactTypeEnum.HEAT_NET.getType().equalsIgnoreCase(artifactType) + || ArtifactTypeEnum.HEAT_ENV.getType().equalsIgnoreCase(artifactType)) { + isValidPayload = validateDeploymentHeatPayload(decodedPayload, artifactType); + if (isValidPayload.isLeft()) { + isValidPayload = extractHeatParameters(artifactInfo); + } + } else if (ArtifactTypeEnum.YANG_XML.getType().equalsIgnoreCase(artifactType) || ArtifactTypeEnum.VNF_CATALOG.getType().equalsIgnoreCase(artifactType) || ArtifactTypeEnum.VF_LICENSE.getType().equalsIgnoreCase(artifactType) + || ArtifactTypeEnum.VENDOR_LICENSE.getType().equalsIgnoreCase(artifactType) || ArtifactTypeEnum.MODEL_INVENTORY_PROFILE.getType().equalsIgnoreCase(artifactType) + || ArtifactTypeEnum.MODEL_QUERY_SPEC.getType().equalsIgnoreCase(artifactType)) { + isValidPayload = validateYangPayload(decodedPayload, artifactType); + // else + // if(ArtifactTypeEnum.APPC_CONFIG.getType().equalsIgnoreCase(artifactType) + // || ){ + } else if (ArtifactTypeEnum.DCAE_INVENTORY_JSON.getType().equalsIgnoreCase(artifactType) || ArtifactTypeEnum.DCAE_INVENTORY_TOSCA.getType().equalsIgnoreCase(artifactType)) { + String artifactFileName = artifactInfo.getArtifactName(); + String fileExtension = GeneralUtility.getFilenameExtension(artifactFileName).toLowerCase(); + switch (fileExtension) { + case "xml": + isValidPayload = validateYangPayload(decodedPayload, artifactType); + break; + case "json": + isValidPayload = validateJsonPayload(decodedPayload, artifactType); + break; + case "yml": + case "yaml": + isValidPayload = validateYmlPayload(decodedPayload, artifactType); + break; + } + } + } + if (isValidPayload.isRight()) { + ResponseFormat responseFormat = isValidPayload.right().value(); + return Either.right(responseFormat); + } + + } // null/empty payload is normal if called from metadata update ONLY. + // The validation of whether this is metadata/payload update case is + // currently done separately + else { + if (!isArtifactMetadataUpdate) { + log.debug("Payload is missing."); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_PAYLOAD); + return Either.right(responseFormat); + } + } + log.trace("Ended payload handling"); + return Either.left(decodedPayload); + } + + private Either<Boolean, ResponseFormat> validateDeploymentHeatPayload(byte[] payload, String artifactType) { + // Basic YAML validation + YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter(); + if (!yamlToObjectConverter.isValidYaml(payload)) { + log.debug("Invalid YAML format"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML, artifactType); + return Either.right(responseFormat); + } + if (!ArtifactTypeEnum.HEAT_ENV.getType().equalsIgnoreCase(artifactType)) { + // HEAT specific YAML validation + DeploymentArtifactHeatConfiguration heatConfiguration = yamlToObjectConverter.convert(payload, DeploymentArtifactHeatConfiguration.class); + if (heatConfiguration == null || heatConfiguration.getHeat_template_version() == null || heatConfiguration.getResources() == null) { + log.debug("HEAT doesn't contain required \"heat_template_version\" and \"resources\" sections "); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT, artifactType); + return Either.right(responseFormat); + } + } + + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateYmlPayload(byte[] decodedPayload, String artifactType) { + Either<Boolean, ResponseFormat> res = Either.left(true); + YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter(); + if (!yamlToObjectConverter.isValidYaml(decodedPayload)) { + log.debug("Invalid YAML format"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML, artifactType); + res = Either.right(responseFormat); + } + + return res; + } + + private Either<Boolean, ResponseFormat> validateYangPayload(byte[] payload, String artifactType) { + boolean isXmlValid = isValidXml(payload); + if (!isXmlValid) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.INVALID_XML, artifactType); + log.debug("Invalid XML content"); + return Either.right(responseFormat); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateJsonPayload(byte[] payload, String type) { + boolean isJsonValid = isValidJson(payload); + if (!isJsonValid) { + ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus.INVALID_JSON, type); + log.debug("Invalid JSON content"); + return Either.right(responseFormat); + } + return Either.left(true); + } + + public void handleTransaction(Either<Operation, ResponseFormat> opState) { + if (opState == null || opState.isRight()) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + } + + public Either<Operation, ResponseFormat> deleteArtifactByInterface(String resourceId, String interfaceType, String operationName, String userId, String artifactId, ImmutablePair<User, Resource> userResourceAuditPair, boolean shouldLock, + boolean inTransaction) { + User user = new User(); + user.setUserId(userId); + Either<Resource, StorageOperationStatus> parent = resourceOperation.getResource(resourceId); + if (parent.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(parent.right().value())); + return Either.right(responseFormat); + } + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDelete = handleDelete(resourceId, artifactId, user, AuditingActionEnum.ARTIFACT_DELETE, ComponentTypeEnum.RESOURCE, parent.left().value(), interfaceType, operationName, + false, inTransaction); + if (handleDelete.isRight()) { + return Either.right(handleDelete.right().value()); + } + Either<ArtifactDefinition, Operation> result = handleDelete.left().value(); + return Either.left(result.right().value()); + + } + + public StorageOperationStatus deleteAllComponentArtifactsIfNotOnGraph(List<ArtifactDefinition> artifacts) { + + if (artifacts != null && !artifacts.isEmpty()) { + for (ArtifactDefinition artifactDefinition : artifacts) { + String esId = artifactDefinition.getEsId(); + if (esId != null && !esId.isEmpty()) { + StorageOperationStatus deleteIfNotOnGraph = deleteIfNotOnGraph(artifactDefinition.getUniqueId(), esId, false); + if (!deleteIfNotOnGraph.equals(StorageOperationStatus.OK)) { + return deleteIfNotOnGraph; + } + } + } + } + return StorageOperationStatus.OK; + } + + private Operation convertToOperation(ArtifactDefinition artifactInfo, String operationName) { + Operation op = new Operation(); + long time = System.currentTimeMillis(); + op.setCreationDate(time); + + String artifactName = artifactInfo.getArtifactName(); + artifactInfo.setArtifactName(createInterfaceArtifactNameFromOperation(operationName, artifactName)); + + op.setImplementation(artifactInfo); + op.setLastUpdateDate(time); + return op; + } + + private String createInterfaceArtifactNameFromOperation(String operationName, String artifactName) { + String newArtifactName = operationName + "_" + artifactName; + log.trace("converting artifact name {} to {}", artifactName, newArtifactName); + return newArtifactName; + } + + public StorageOperationStatus deleteIfNotOnGraph(String artifactId, String artifactEsId, boolean deleteOnlyPayload) { + log.debug("deleteIfNotOnGraph: delete only payload = {}", deleteOnlyPayload); + Either<ArtifactData, TitanOperationStatus> checkArtifactNode = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ArtifactRef), artifactId, ArtifactData.class); + if ((artifactEsId != null && !artifactEsId.isEmpty())) { + boolean isNotExistOnGraph = checkArtifactNode.isRight() && checkArtifactNode.right().value().equals(TitanOperationStatus.NOT_FOUND); + + if ((isNotExistOnGraph) || (checkArtifactNode.left().value().getArtifactDataDefinition().getMandatory() && deleteOnlyPayload) + || (ArtifactGroupTypeEnum.SERVICE_API.equals(checkArtifactNode.left().value().getArtifactDataDefinition().getArtifactGroupType()) && deleteOnlyPayload)) { + // last one. need to delete in ES + log.debug("Entry on graph is deleted. Delete artifact in ES for id = {}", artifactEsId); + artifactCassandraDao.deleteArtifact(artifactEsId); + return StorageOperationStatus.OK; + // return + // componentsUtils.getResponseFormatByResourceId(ActionStatus.OK, + // resourceId); + + } else { + log.debug("Entry on graph is deleted. Exist more connections on this artifact. Don't delete artifact in ES for id = {}", artifactEsId); + return StorageOperationStatus.OK; + } + + } + return StorageOperationStatus.OK; + } + + // download by MSO + public Either<byte[], ResponseFormat> downloadRsrcArtifactByNames(String serviceName, String serviceVersion, String resourceName, String resourceVersion, String artifactName) { + + // General validation + if (serviceName == null || serviceVersion == null || resourceName == null || resourceVersion == null || artifactName == null) { + log.debug("One of the function parameteres is null"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + // Normalizing artifact name + artifactName = ValidationUtils.normalizeFileName(artifactName); + + // Resource validation + Either<Resource, ResponseFormat> validateResourceNameAndVersion = validateResourceNameAndVersion(resourceName, resourceVersion); + if (validateResourceNameAndVersion.isRight()) { + return Either.right(validateResourceNameAndVersion.right().value()); + } + + Resource resource = validateResourceNameAndVersion.left().value(); + String resourceId = resource.getUniqueId(); + + // Service validation + Either<Service, ResponseFormat> validateServiceNameAndVersion = validateServiceNameAndVersion(serviceName, serviceVersion); + if (validateServiceNameAndVersion.isRight()) { + return Either.right(validateServiceNameAndVersion.right().value()); + } + + Map<String, ArtifactDefinition> artifacts = resource.getDeploymentArtifacts(); + if (artifacts == null || artifacts.isEmpty()) { + log.debug("Deployment artifacts of resource {} are not found", resourceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactName)); + } + + ArtifactDefinition deploymentArtifact = null; + + for (ArtifactDefinition artifactDefinition : artifacts.values()) { + if (artifactDefinition.getArtifactName() != null && artifactDefinition.getArtifactName().equals(artifactName)) { + log.debug("Found deployment artifact {}", artifactName); + deploymentArtifact = artifactDefinition; + break; + } + } + + if (deploymentArtifact == null) { + log.debug("No deployment artifact {} was found for resource {}", artifactName, resourceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactName)); + } + + // Downloading the artifact + Either<ImmutablePair<String, byte[]>, ResponseFormat> downloadArtifactEither = downloadArtifact(deploymentArtifact); + if (downloadArtifactEither.isRight()) { + log.debug("Download artifact {} failed", artifactName); + return Either.right(downloadArtifactEither.right().value()); + } + log.trace("Download of resource artifact succeeded, uniqueId {}", deploymentArtifact.getUniqueId()); + return Either.left(downloadArtifactEither.left().value().getRight()); + } + + // download by MSO + public Either<byte[], ResponseFormat> downloadRsrcInstArtifactByNames(String serviceName, String serviceVersion, String resourceInstanceName, String artifactName) { + + // General validation + if (serviceName == null || serviceVersion == null || resourceInstanceName == null || artifactName == null) { + log.debug("One of the function parameteres is null"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + // Normalizing artifact name + artifactName = ValidationUtils.normalizeFileName(artifactName); + + // Resource validation + /* + * Either<Resource, ResponseFormat> validateResourceNameAndVersion = validateResourceNameAndVersion(resourceName, resourceVersion); if (validateResourceNameAndVersion.isRight()) { return + * Either.right(validateResourceNameAndVersion.right().value()); } + * + * Resource resource = validateResourceNameAndVersion.left().value(); String resourceId = resource.getUniqueId(); + */ + + // Service validation + Either<Service, ResponseFormat> validateServiceNameAndVersion = validateServiceNameAndVersion(serviceName, serviceVersion); + if (validateServiceNameAndVersion.isRight()) { + return Either.right(validateServiceNameAndVersion.right().value()); + } + + Service service = validateServiceNameAndVersion.left().value(); + + // ResourceInstance validation + Either<ComponentInstance, ResponseFormat> validateResourceInstance = validateResourceInstance(service, resourceInstanceName); + if (validateResourceInstance.isRight()) { + return Either.right(validateResourceInstance.right().value()); + } + + ComponentInstance resourceInstance = validateResourceInstance.left().value(); + + Map<String, ArtifactDefinition> artifacts = resourceInstance.getDeploymentArtifacts(); + + final String finalArtifactName = artifactName; + Predicate<ArtifactDefinition> filterArtifactByName = p -> p.getArtifactName().equals(finalArtifactName); + + boolean hasDeploymentArtifacts = artifacts != null && artifacts.values().stream().anyMatch(filterArtifactByName); + ArtifactDefinition deployableArtifact; + + if (!hasDeploymentArtifacts) { + log.debug("Deployment artifact with name {} not found", artifactName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactName)); + } + + log.debug("Found deployment artifact {}", artifactName); + deployableArtifact = artifacts.values().stream().filter(filterArtifactByName).findFirst().get(); + // Downloading the artifact + Either<ImmutablePair<String, byte[]>, ResponseFormat> downloadArtifactEither = downloadArtifact(deployableArtifact); + + if (downloadArtifactEither.isRight()) { + log.debug("Download artifact {} failed", artifactName); + return Either.right(downloadArtifactEither.right().value()); + } + log.trace("Download of resource artifact succeeded, uniqueId {}", deployableArtifact.getUniqueId()); + return Either.left(downloadArtifactEither.left().value().getRight()); + } + + private Either<ComponentInstance, ResponseFormat> validateResourceInstance(Service service, String resourceInstanceName) { + + List<ComponentInstance> riList = service.getComponentInstances(); + for (ComponentInstance ri : riList) { + if (ri.getNormalizedName().equals(resourceInstanceName)) + return Either.left(ri); + } + + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND, resourceInstanceName)); + } + + private Either<Service, ResponseFormat> validateServiceNameAndVersion(String serviceName, String serviceVersion) { + + Either<List<Service>, StorageOperationStatus> serviceListBySystemName = serviceOperation.getServiceListBySystemName(serviceName, false); + if (serviceListBySystemName.isRight()) { + log.debug("Couldn't fetch any service with name {}", serviceName); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(serviceListBySystemName.right().value(), ComponentTypeEnum.SERVICE), serviceName)); + } + List<Service> serviceList = serviceListBySystemName.left().value(); + if (serviceList == null || serviceList.isEmpty()) { + log.debug("Couldn't fetch any service with name {}", serviceName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.SERVICE_NOT_FOUND, serviceName)); + } + + Service foundService = null; + for (Service service : serviceList) { + if (service.getVersion().equals(serviceVersion)) { + log.trace("Found service with version {}", serviceVersion); + foundService = service; + break; + } + } + + if (foundService == null) { + log.debug("Couldn't find version {} for service {}", serviceVersion, serviceName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_VERSION_NOT_FOUND, ComponentTypeEnum.SERVICE.getValue(), serviceVersion)); + } + return Either.left(foundService); + } + + private Either<Resource, ResponseFormat> validateResourceNameAndVersion(String resourceName, String resourceVersion) { + Either<List<Resource>, StorageOperationStatus> resourceListBySystemName = resourceOperation.getResourceListBySystemName(resourceName, false); + if (resourceListBySystemName.isRight()) { + log.debug("Couldn't fetch any resource with name {}", resourceName); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resourceListBySystemName.right().value()), resourceName)); + } + List<Resource> resourceList = resourceListBySystemName.left().value(); + if (resourceList == null || resourceList.isEmpty()) { + log.debug("Couldn't fetch any resource with name {}", resourceName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceName)); + } + + Resource foundResource = null; + for (Resource resource : resourceList) { + if (resource.getVersion().equals(resourceVersion)) { + log.trace("Found resource with version {}", resourceVersion); + foundResource = resource; + break; + } + } + + if (foundResource == null) { + log.debug("Couldn't find version {} for resource {}", resourceVersion, resourceName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_VERSION_NOT_FOUND, ComponentTypeEnum.RESOURCE.getValue(), resourceVersion)); + } + return Either.left(foundResource); + } + + public Either<byte[], ResponseFormat> downloadServiceArtifactByNames(String serviceName, String serviceVersion, String artifactName) { + // Validation + log.trace("Starting download of service interface artifact, serviceName {}, serviceVersion {}, artifact name {}", serviceName, serviceVersion, artifactName); + if (serviceName == null || serviceVersion == null || artifactName == null) { + log.debug("One of the function parameteres is null"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + // Normalizing artifact name + artifactName = ValidationUtils.normalizeFileName(artifactName); + + // Service validation + Either<Service, ResponseFormat> validateServiceNameAndVersion = validateServiceNameAndVersion(serviceName, serviceVersion); + if (validateServiceNameAndVersion.isRight()) { + return Either.right(validateServiceNameAndVersion.right().value()); + } + + String serviceId = validateServiceNameAndVersion.left().value().getUniqueId(); + + // Looking for deployment artifacts + Service service = validateServiceNameAndVersion.left().value(); + Map<String, ArtifactDefinition> artifacts = service.getDeploymentArtifacts(); + if (artifacts == null || artifacts.isEmpty()) { + log.debug("Deployment artifacts of service {} are not found", serviceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactName)); + } + + ArtifactDefinition deploymentArtifact = null; + + for (ArtifactDefinition artifactDefinition : artifacts.values()) { + if (artifactDefinition.getArtifactName().equals(artifactName)) { + log.debug("Found deployment artifact {}", artifactName); + deploymentArtifact = artifactDefinition; + } + } + + if (deploymentArtifact == null) { + log.debug("No deployment artifact {} was found for service {}", artifactName, serviceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactName)); + } + + // Downloading the artifact + Either<ImmutablePair<String, byte[]>, ResponseFormat> downloadArtifactEither = downloadArtifact(deploymentArtifact); + if (downloadArtifactEither.isRight()) { + log.debug("Download artifact {} failed", artifactName); + return Either.right(downloadArtifactEither.right().value()); + } + log.trace("Download of service artifact succeeded, uniqueId {}", deploymentArtifact.getUniqueId()); + return Either.left(downloadArtifactEither.left().value().getRight()); + } + + public Either<ImmutablePair<String, byte[]>, ResponseFormat> downloadArtifact(String artifactUniqueId) { + log.trace("Starting download of artifact, uniqueId {}", artifactUniqueId); + Either<ArtifactDefinition, StorageOperationStatus> artifactById = artifactOperation.getArtifactById(artifactUniqueId, false); + if (artifactById.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(artifactById.right().value()); + log.debug("Error when getting artifact info by id{}, error: {}", artifactUniqueId, actionStatus.name()); + return Either.right(componentsUtils.getResponseFormatByArtifactId(actionStatus, "")); + } + ArtifactDefinition artifactDefinition = artifactById.left().value(); + if (artifactDefinition == null) { + log.debug("Empty artifact definition returned from DB by artifact id {}", artifactUniqueId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, "")); + } + + return downloadArtifact(artifactDefinition); + } + + private boolean checkArtifactInComponent(org.openecomp.sdc.be.model.Component component, String artifactId) { + boolean found = false; + Map<String, ArtifactDefinition> artifactsS = component.getArtifacts(); + if (artifactsS != null) { + for (Map.Entry<String, ArtifactDefinition> entry : artifactsS.entrySet()) { + if (entry.getValue().getUniqueId().equals(artifactId)) { + found = true; + break; + } + } + } + Map<String, ArtifactDefinition> deploymentArtifactsS = component.getDeploymentArtifacts(); + if (!found && deploymentArtifactsS != null) { + for (Map.Entry<String, ArtifactDefinition> entry : deploymentArtifactsS.entrySet()) { + if (entry.getValue().getUniqueId().equals(artifactId)) { + found = true; + break; + } + } + } + Map<String, ArtifactDefinition> toscaArtifactsS = component.getToscaArtifacts(); + if (!found && toscaArtifactsS != null) { + for (Map.Entry<String, ArtifactDefinition> entry : toscaArtifactsS.entrySet()) { + if (entry.getValue().getUniqueId().equals(artifactId)) { + found = true; + break; + } + } + } + switch (component.getComponentType()) { + case RESOURCE: + Map<String, InterfaceDefinition> interfaces = ((Resource) component).getInterfaces(); + if (!found && interfaces != null) { + for (Map.Entry<String, InterfaceDefinition> entry : interfaces.entrySet()) { + Map<String, Operation> operations = entry.getValue().getOperations(); + for (Map.Entry<String, Operation> entryOp : operations.entrySet()) { + if (entryOp.getValue().getImplementation() != null && entryOp.getValue().getImplementation().getUniqueId().equals(artifactId)) { + found = true; + break; + } + } + } + } + break; + case SERVICE: + Map<String, ArtifactDefinition> apiArtifacts = ((Service) component).getServiceApiArtifacts(); + if (!found && apiArtifacts != null) { + for (Map.Entry<String, ArtifactDefinition> entry : apiArtifacts.entrySet()) { + if (entry.getValue().getUniqueId().equals(artifactId)) { + found = true; + break; + } + } + } + break; + default: + + } + + return found; + } + + private boolean checkArtifactInResourceInstance(Component component, String resourceInstanceId, String artifactId) { + + boolean found = false; + List<ComponentInstance> resourceInstances = component.getComponentInstances(); + ComponentInstance resourceInstance = null; + for (ComponentInstance ri : resourceInstances) { + if (ri.getUniqueId().equals(resourceInstanceId)) { + resourceInstance = ri; + break; + } + } + if (resourceInstance != null) { + Map<String, ArtifactDefinition> artifacts = resourceInstance.getDeploymentArtifacts(); + if (artifacts != null) { + for (Map.Entry<String, ArtifactDefinition> entry : artifacts.entrySet()) { + if (entry.getValue().getUniqueId().equals(artifactId)) { + found = true; + break; + } + } + } + } + return found; + } + + private Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists(String componentId, String userId, AuditingActionEnum auditingAction, User user, String artifactId, ComponentTypeEnum componentType, + String containerComponentType, boolean inTransaction) { + + NodeTypeEnum nodeType = componentType.getNodeType(); + if (containerComponentType != null && NodeTypeEnum.ResourceInstance == nodeType) { + nodeType = (ComponentTypeEnum.findByParamName(containerComponentType)).getNodeType(); + } + ComponentOperation componentOperation = getComponentOperation(nodeType); + + if (componentOperation == null) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + log.debug("addArtifact - not supported component type {}", componentType); + handleAuditing(auditingAction, null, componentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + Either<? extends org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentResult = componentOperation.getComponent(componentId, inTransaction); + + if (componentResult.isRight()) { + ActionStatus status = (componentType.equals(ComponentTypeEnum.RESOURCE)) ? ActionStatus.RESOURCE_NOT_FOUND : ActionStatus.SERVICE_NOT_FOUND; + ComponentTypeEnum componentForAudit = (componentType.equals(ComponentTypeEnum.RESOURCE)) ? ComponentTypeEnum.RESOURCE : ComponentTypeEnum.SERVICE; + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(status, componentId); + log.debug("Service not found, serviceId {}", componentId); + handleAuditing(auditingAction, null, componentId, user, null, null, artifactId, responseFormat, componentForAudit, null); + return Either.right(responseFormat); + } + return Either.left(componentResult.left().value()); + } + + private Either<Boolean, ResponseFormat> validateWorkOnComponent(org.openecomp.sdc.be.model.Component component, String userId, AuditingActionEnum auditingAction, User user, String artifactId, ArtifactOperation operation, + ComponentTypeEnum componentType) { + if (operation != ArtifactOperation.Download) { + Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId); + if (canWork.isRight()) { + String uniqueId = component.getUniqueId(); + log.debug("Service status isn't CHECKOUT or user isn't owner, serviceId {}", uniqueId); + handleAuditing(auditingAction, component, uniqueId, user, null, null, artifactId, canWork.right().value(), component.getComponentType(), null); + return Either.right(canWork.right().value()); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateWorkOnResource(Resource resource, String userId, AuditingActionEnum auditingAction, User user, String artifactId, ArtifactOperation operation) { + if (operation != ArtifactOperation.Download) { + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + String uniqueId = resource.getUniqueId(); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + log.debug("Resource status isn't CHECKOUT or user isn't owner, resourceId {}", uniqueId); + handleAuditing(auditingAction, resource, uniqueId, user, null, null, artifactId, responseFormat, ComponentTypeEnum.RESOURCE, null); + return Either.right(responseFormat); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateUserRole(User user, AuditingActionEnum auditingAction, String componentId, String artifactId, ComponentTypeEnum componentType, ArtifactOperation operation) { + + if (operation != ArtifactOperation.Download) { + String role = user.getRole(); + if (!role.equals(Role.ADMIN.name()) && !role.equals(Role.DESIGNER.name())) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + log.debug("addArtifact - user isn't permitted to perform operation, userId {}, role {}", user.getUserId(), role); + handleAuditing(auditingAction, null, componentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + } + return Either.left(true); + } + + private Either<User, ResponseFormat> validateUserExists(String userId, AuditingActionEnum auditingAction, String componentId, String artifactId, ComponentTypeEnum componentType) { + + return validateUserExists(userId, auditingAction, componentId, artifactId, componentType, false); + + } + + private Either<User, ResponseFormat> validateUserExists(String userId, AuditingActionEnum auditingAction, String componentId, String artifactId, ComponentTypeEnum componentType, boolean inTransaction) { + Either<User, ResponseFormat> validateUserExists = validateUserExists(userId, auditingAction.getName(), inTransaction); + + if (validateUserExists.isRight()) { + User user = new User(); + user.setUserId(userId); + handleAuditing(auditingAction, null, componentId, user, null, null, artifactId, validateUserExists.right().value(), componentType, null); + return Either.right(validateUserExists.right().value()); + } + return Either.left(validateUserExists.left().value()); + } + + private AuditingActionEnum detectAuditingType(ArtifactOperation operation, String origMd5) { + AuditingActionEnum auditingAction = null; + switch (operation) { + case Create: + auditingAction = operation.isExternalApi() ? AuditingActionEnum.ARTIFACT_UPLOAD_BY_API : AuditingActionEnum.ARTIFACT_UPLOAD; + break; + case Update: + auditingAction = operation.isExternalApi() ? AuditingActionEnum.ARTIFACT_UPLOAD_BY_API : origMd5 == null ? AuditingActionEnum.ARTIFACT_METADATA_UPDATE : AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE; + break; + case Delete: + auditingAction = operation.isExternalApi() ? AuditingActionEnum.ARTIFACT_DELETE_BY_API : AuditingActionEnum.ARTIFACT_DELETE; + break; + case Download: + auditingAction = operation.isExternalApi() ? AuditingActionEnum.DOWNLOAD_ARTIFACT : AuditingActionEnum.ARTIFACT_DOWNLOAD; + break; + default: + break; + } + return auditingAction; + } + + private Either<ImmutablePair<String, byte[]>, ResponseFormat> downloadArtifact(ArtifactDefinition artifactDefinition) { + String esArtifactId = artifactDefinition.getEsId(); + Either<ESArtifactData, CassandraOperationStatus> artifactfromES = artifactCassandraDao.getArtifact(esArtifactId); + if (artifactfromES.isRight()) { + CassandraOperationStatus resourceUploadStatus = artifactfromES.right().value(); + StorageOperationStatus storageResponse = DaoStatusConverter.convertCassandraStatusToStorageStatus(resourceUploadStatus); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageResponse); + log.debug("Error when getting artifact from ES, error: {}", actionStatus.name()); + return Either.right(componentsUtils.getResponseFormatByArtifactId(actionStatus, artifactDefinition.getArtifactDisplayName())); + } + + ESArtifactData esArtifactData = artifactfromES.left().value(); + byte[] data = esArtifactData.getDataAsArray(); + if (data == null) { + log.debug("Artifact data from ES is null"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactDefinition.getArtifactDisplayName())); + } + String artifactName = artifactDefinition.getArtifactName(); + log.trace("Download of artifact succeeded, uniqueId {}, artifact file name {}", artifactDefinition.getUniqueId(), artifactName); + return Either.left(new ImmutablePair<String, byte[]>(artifactName, data)); + } + + public ESArtifactData createEsArtifactData(ArtifactDataDefinition artifactInfo, byte[] artifactPayload) { + ESArtifactData artifactData = new ESArtifactData(artifactInfo.getEsId(), artifactPayload); + return artifactData; + } + + private boolean saveArtifacts(ESArtifactData artifactData, String resourceId, boolean reload) { + + CassandraOperationStatus resourceUploadStatus = artifactCassandraDao.saveArtifact(artifactData); + + if (resourceUploadStatus.equals(CassandraOperationStatus.OK)) { + log.debug("Artifact {} was saved in component {}.", artifactData.getId(), resourceId); + } else { + log.info("Failed to save artifact {}.", artifactData.getId()); + return false; + } + return true; + } + + private boolean isArtifactMetadataUpdate(AuditingActionEnum auditingActionEnum) { + return (auditingActionEnum.equals(AuditingActionEnum.ARTIFACT_METADATA_UPDATE)); + } + + private boolean isDeploymentArtifact(ArtifactDefinition artifactInfo) { + return (ArtifactGroupTypeEnum.DEPLOYMENT.equals(artifactInfo.getArtifactGroupType())); + } + + public IResourceOperation getResourceOperation() { + return this.resourceOperation; + } + + public Either<ArtifactDefinition, ResponseFormat> createArtifactPlaceHolderInfo(String resourceId, String logicalName, Map<String, Object> artifactInfoMap, String userId, ArtifactGroupTypeEnum groupType, boolean inTransaction) { + Either<User, ActionStatus> user = userAdminManager.getUser(userId, inTransaction); + if (user.isRight()) { + ResponseFormat responseFormat; + if (user.right().value().equals(ActionStatus.USER_NOT_FOUND)) { + log.debug("create artifact placeholder - not authorized user, userId {}", userId); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + } else { + log.debug("create artifact placeholder - failed to authorize user, userId {}", userId); + responseFormat = componentsUtils.getResponseFormat(user.right().value()); + } + return Either.right(responseFormat); + } + + ArtifactDefinition artifactDefinition = createArtifactPlaceHolderInfo(resourceId, logicalName, artifactInfoMap, user.left().value(), groupType); + return Either.left(artifactDefinition); + } + + public ArtifactDefinition createArtifactPlaceHolderInfo(String resourceId, String logicalName, Map<String, Object> artifactInfoMap, User user, ArtifactGroupTypeEnum groupType) { + ArtifactDefinition artifactInfo = new ArtifactDefinition(); + + String artifactName = (String) artifactInfoMap.get(ARTIFACT_PLACEHOLDER_DISPLAY_NAME); + String artifactType = (String) artifactInfoMap.get(ARTIFACT_PLACEHOLDER_TYPE); + String artifactDescription = (String) artifactInfoMap.get(ARTIFACT_PLACEHOLDER_DESCRIPTION); + + artifactInfo.setArtifactDisplayName(artifactName); + artifactInfo.setArtifactLabel(logicalName.toLowerCase()); + artifactInfo.setArtifactType(artifactType); + artifactInfo.setDescription(artifactDescription); + artifactInfo.setArtifactGroupType(groupType); + setDefaultArtifactTimeout(groupType, artifactInfo); + + setArtifactPlaceholderCommonFields(resourceId, user, artifactInfo); + + return artifactInfo; + } + + private void setDefaultArtifactTimeout(ArtifactGroupTypeEnum groupType, ArtifactDefinition artifactInfo) { + if (groupType.equals(ArtifactGroupTypeEnum.DEPLOYMENT)) { + artifactInfo.setTimeout(defaultHeatTimeout); + } else { + artifactInfo.setTimeout(NON_HEAT_TIMEOUT); + } + } + + private void setArtifactPlaceholderCommonFields(String resourceId, User user, ArtifactDefinition artifactInfo) { + String uniqueId = null; + + if (resourceId != null) { + uniqueId = UniqueIdBuilder.buildPropertyUniqueId(resourceId.toLowerCase(), artifactInfo.getArtifactLabel().toLowerCase()); + artifactInfo.setUniqueId(uniqueId); + } + artifactInfo.setUserIdCreator(user.getUserId()); + String fullName = user.getFullName(); + artifactInfo.setUpdaterFullName(fullName); + + long time = System.currentTimeMillis(); + + artifactInfo.setCreatorFullName(fullName); + artifactInfo.setCreationDate(time); + + artifactInfo.setLastUpdateDate(time); + artifactInfo.setUserIdLastUpdater(user.getUserId()); + + artifactInfo.setMandatory(true); + } + + public Either<Map<String, ArtifactDefinition>, StorageOperationStatus> getArtifacts(String parentId, NodeTypeEnum parentType, boolean inTransaction, ArtifactGroupTypeEnum groupType) { + return artifactOperation.getArtifacts(parentId, parentType, inTransaction, groupType.getType()); + } + + public Either<ArtifactDefinition, StorageOperationStatus> addHeatEnvArtifact(ArtifactDefinition artifactHeatEnv, ArtifactDefinition artifact, String parentId, NodeTypeEnum parentType, boolean inTransaction) { + return artifactOperation.addHeatEnvArtifact(artifactHeatEnv, artifact, parentId, parentType, inTransaction); + + } + + private Either<ESArtifactData, ResponseFormat> createEsHeatEnvArtifactDataFromString(ArtifactDefinition artifactDefinition, String parameters) { + StringBuilder sb = new StringBuilder(); + + sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactHeader()); + sb.append(parameters); + sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactFooter()); + byte[] payload = sb.toString().getBytes(); + + YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter(); + + /* + * if (!yamlToObjectConverter.isValidYaml(payload)) { log.debug("Invalid YAML format"); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML, ArtifactTypeEnum.HEAT_ENV.getType()); return + * Either.right(responseFormat); } + */ + + ESArtifactData artifactData = createEsArtifactData(artifactDefinition, payload); + return Either.left(artifactData); + } + + /** + * + * @param artifactDefinition + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> generateHeatEnvArtifact(ArtifactDefinition artifactDefinition, org.openecomp.sdc.be.model.Component component, String resourceInstanceName, User modifier, boolean shouldLock) { + List<HeatParameterDefinition> heatParameters = artifactDefinition.getHeatParameters(); + heatParameters.sort(Comparator.comparing(e -> e.getName())); + StringBuilder sb = new StringBuilder("parameters:\n"); + if (heatParameters != null) { + + for (HeatParameterDefinition heatParameterDefinition : heatParameters) { + if (heatParameterDefinition.getCurrentValue() != null) { + HeatParameterType type = HeatParameterType.isValidType(heatParameterDefinition.getType()); + if (type != null) { + switch (type) { + case BOOLEAN: + sb.append(" ").append(heatParameterDefinition.getName()).append(":").append(" ").append(Boolean.parseBoolean(heatParameterDefinition.getCurrentValue())).append("\n"); + break; + case NUMBER: + // if + // (ValidationUtils.isFloatNumber(heatParameterDefinition.getCurrentValue())) + // { + // sb.append(" + // ").append(heatParameterDefinition.getName()).append(":").append(" + // ").append(Float.parseFloat(heatParameterDefinition.getCurrentValue())).append("\n"); + // } else { + // sb.append(" + // ").append(heatParameterDefinition.getName()).append(":").append(" + // ").append(Integer.parseInt(heatParameterDefinition.getCurrentValue())).append("\n"); + // } + sb.append(" ").append(heatParameterDefinition.getName()).append(":").append(" ").append(new BigDecimal(heatParameterDefinition.getCurrentValue()).toPlainString()).append("\n"); + break; + case COMMA_DELIMITED_LIST: + case JSON: + sb.append(" ").append(heatParameterDefinition.getName()).append(":").append(" ").append(heatParameterDefinition.getCurrentValue()).append("\n"); + break; + default: + String value = heatParameterDefinition.getCurrentValue(); + boolean starts = value.startsWith("\""); + boolean ends = value.endsWith("\""); + if (!(starts && ends)) { + starts = value.startsWith("'"); + ends = value.endsWith("'"); + if (!(starts && ends)) { + value = "\"" + value + "\""; + } + } + sb.append(" ").append(heatParameterDefinition.getName()).append(":").append(" ").append(value); + sb.append("\n"); + break; + + } + } + } + } + } + return generateAndSaveHeatEnvArtifact(artifactDefinition, sb.toString(), component, resourceInstanceName, modifier, shouldLock); + + } + + /** + * + * @param artifactDefinition + * @param payload + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> generateAndSaveHeatEnvArtifact(ArtifactDefinition artifactDefinition, String payload, org.openecomp.sdc.be.model.Component component, String resourceInstanceName, User modifier, + boolean shouldLock) { + return generateArtifactPayload(artifactDefinition, component, resourceInstanceName, modifier, shouldLock, () -> artifactDefinition.getHeatParamsUpdateDate(), () -> createEsHeatEnvArtifactDataFromString(artifactDefinition, payload)); + + } + + protected Either<ArtifactDefinition, ResponseFormat> generateArtifactPayload(ArtifactDefinition artifactDefinition, org.openecomp.sdc.be.model.Component component, String resourceInstanceName, User modifier, boolean shouldLock, + Supplier<Long> payloadUpdateDateGen, Supplier<Either<ESArtifactData, ResponseFormat>> esDataCreator) { + + if (artifactDefinition.getPayloadUpdateDate() == null || artifactDefinition.getPayloadUpdateDate() == 0 || artifactDefinition.getPayloadUpdateDate() < payloadUpdateDateGen.get()) { + + log.trace("Generaing payload for {} artifact {}", artifactDefinition.getArtifactType(), artifactDefinition.getEsId()); + Either<ESArtifactData, ResponseFormat> artifactDataRes = esDataCreator.get(); + ESArtifactData artifactData = null; + + if (artifactDataRes.isLeft()) { + artifactData = artifactDataRes.left().value(); + } else { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + handleAuditing(AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE, component, component.getUniqueId(), modifier, artifactDefinition, artifactDefinition.getUniqueId(), artifactDefinition.getUniqueId(), responseFormat, + ComponentTypeEnum.RESOURCE_INSTANCE, resourceInstanceName); + + return Either.right(artifactDataRes.right().value()); + } + String newCheckSum = GeneralUtility.calculateMD5ByByteArray(artifactData.getDataAsArray()); + String oldCheckSum; + String esArtifactId = artifactDefinition.getEsId(); + Either<ESArtifactData, CassandraOperationStatus> artifactfromES; + ESArtifactData esArtifactData; + if (esArtifactId != null && !esArtifactId.isEmpty()) { + artifactfromES = artifactCassandraDao.getArtifact(esArtifactId); + if (artifactfromES.isRight()) { + CassandraOperationStatus resourceUploadStatus = artifactfromES.right().value(); + StorageOperationStatus storageResponse = DaoStatusConverter.convertCassandraStatusToStorageStatus(resourceUploadStatus); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageResponse); + log.debug("Error when getting artifact from ES, error: {}", actionStatus.name()); + return Either.right(componentsUtils.getResponseFormatByArtifactId(actionStatus, artifactDefinition.getArtifactDisplayName())); + } + esArtifactData = artifactfromES.left().value(); + oldCheckSum = GeneralUtility.calculateMD5ByByteArray(esArtifactData.getDataAsArray()); + } else { + oldCheckSum = artifactDefinition.getArtifactChecksum(); + } + Either<ArtifactDefinition, StorageOperationStatus> updateArifactDefinitionStatus; + + if (shouldLock) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, "Update Artifact - lock resource: "); + if (lockComponent.isRight()) { + handleAuditing(AuditingActionEnum.ARTIFACT_METADATA_UPDATE, component, component.getUniqueId(), modifier, null, null, artifactDefinition.getUniqueId(), lockComponent.right().value(), component.getComponentType(), null); + return Either.right(lockComponent.right().value()); + } + } + try { + if (oldCheckSum != null && oldCheckSum.equals(newCheckSum)) { + + artifactDefinition.setPayloadUpdateDate(payloadUpdateDateGen.get()); + updateArifactDefinitionStatus = artifactOperation.updateArifactDefinition(artifactDefinition, false); + log.trace("No real update done in payload for {} artifact, updating payloadUpdateDate {}", artifactDefinition.getArtifactType(), artifactDefinition.getEsId()); + if (updateArifactDefinitionStatus.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(updateArifactDefinitionStatus.right().value()), artifactDefinition.getArtifactDisplayName()); + log.trace("Failed to update payloadUpdateDate ", artifactDefinition.getEsId()); + handleAuditing(AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE, component, component.getUniqueId(), modifier, artifactDefinition, artifactDefinition.getUniqueId(), artifactDefinition.getUniqueId(), responseFormat, + ComponentTypeEnum.RESOURCE_INSTANCE, resourceInstanceName); + + return Either.right(responseFormat); + } + } else { + + oldCheckSum = artifactDefinition.getArtifactChecksum(); + artifactDefinition.setArtifactChecksum(newCheckSum); + artifactOperation.updateUUID(artifactDefinition, oldCheckSum, artifactDefinition.getArtifactVersion()); + artifactDefinition.setEsId(artifactDefinition.getUniqueId()); + updateArifactDefinitionStatus = artifactOperation.updateArifactDefinition(artifactDefinition, true); + + log.trace("Update Payload ", artifactDefinition.getEsId()); + + if (updateArifactDefinitionStatus.isLeft()) { + + artifactData.setId(artifactDefinition.getUniqueId()); + CassandraOperationStatus saveArtifactStatus = artifactCassandraDao.saveArtifact(artifactData); + + if (saveArtifactStatus.equals(CassandraOperationStatus.OK)) { + titanGenericDao.commit(); + log.debug("Artifact Saved In ES {}", artifactData.getId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleAuditing(AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE, component, component.getUniqueId(), modifier, artifactDefinition, artifactDefinition.getUniqueId(), artifactDefinition.getUniqueId(), responseFormat, + ComponentTypeEnum.RESOURCE_INSTANCE, resourceInstanceName); + + } else { + titanGenericDao.rollback(); + log.info("Failed to save artifact {}.", artifactData.getId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + handleAuditing(AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE, component, component.getUniqueId(), modifier, artifactDefinition, artifactDefinition.getUniqueId(), artifactDefinition.getUniqueId(), responseFormat, + ComponentTypeEnum.RESOURCE_INSTANCE, resourceInstanceName); + + return Either.right(responseFormat); + } + } else { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(updateArifactDefinitionStatus.right().value()), artifactDefinition.getArtifactDisplayName()); + log.debug("Failed To update artifact {}", artifactData.getId()); + handleAuditing(AuditingActionEnum.ARTIFACT_PAYLOAD_UPDATE, component, component.getUniqueId(), modifier, artifactDefinition, artifactDefinition.getUniqueId(), artifactDefinition.getUniqueId(), responseFormat, + ComponentTypeEnum.RESOURCE_INSTANCE, resourceInstanceName); + + return Either.right(responseFormat); + + } + } + } finally { + if (shouldLock) { + graphLockOperation.unlockComponent(component.getUniqueId(), component.getComponentType().getNodeType()); + } + } + } + + return Either.left(artifactDefinition); + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleUpdateHeatEnv(String componentId, ArtifactDefinition artifactInfo, AuditingActionEnum auditingAction, String artifactId, User user, ComponentTypeEnum componentType, + org.openecomp.sdc.be.model.Component parent, String originData, String origMd5, ArtifactOperation operation, boolean shouldLock, boolean inTransaction) { + NodeTypeEnum parentType = convertParentType(componentType); + String parentId = parent.getUniqueId(); + Either<ArtifactDefinition, StorageOperationStatus> artifactRes = artifactOperation.getArtifactById(artifactId, false); + ArtifactDefinition currArtifact = artifactRes.left().value(); + + if (origMd5 != null) { + Either<Boolean, ResponseFormat> validateMd5 = validateMd5(origMd5, originData, artifactInfo.getPayloadData(), operation); + if (validateMd5.isRight()) { + ResponseFormat responseFormat = validateMd5.right().value(); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + + if (artifactInfo.getPayloadData() != null && artifactInfo.getPayloadData().length != 0) { + Either<Boolean, ResponseFormat> deploymentValidationResult = validateDeploymentArtifact(parent, componentId, user.getUserId(), false, artifactInfo, currArtifact, NodeTypeEnum.ResourceInstance); + if (deploymentValidationResult.isRight()) { + ResponseFormat responseFormat = deploymentValidationResult.right().value(); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + + Either<byte[], ResponseFormat> payloadEither = handlePayload(artifactInfo, isArtifactMetadataUpdate(auditingAction)); + if (payloadEither.isRight()) { + ResponseFormat responseFormat = payloadEither.right().value(); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + } else { // duplicate + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, ARTIFACT_PAYLOAD); + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + } + + // lock resource + if (shouldLock) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(parent, "Update Artifact - lock "); + if (lockComponent.isRight()) { + handleAuditing(auditingAction, parent, parentId, user, null, null, artifactId, lockComponent.right().value(), componentType, null); + return Either.right(lockComponent.right().value()); + } + } + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + try { + resultOp = updateHeatEnvParams(componentId, artifactId, artifactInfo, user, auditingAction, parent, componentType, currArtifact, origMd5, inTransaction); + return resultOp; + + } finally { + // unlock resource + if (resultOp == null || resultOp.isRight()) { + log.debug("all changes rollback"); + if (false == inTransaction) + titanGenericDao.rollback(); + } else { + log.debug("all changes committed"); + if (false == inTransaction) + titanGenericDao.commit(); + } + if (shouldLock) + componentType = parent.getComponentType(); + NodeTypeEnum nodeType = componentType.getNodeType(); + graphLockOperation.unlockComponent(parent.getUniqueId(), nodeType); + // graphLockOperation.unlockComponent(parentId, parentType); + } + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> updateHeatEnvParams(String componentId, String artifactId, ArtifactDefinition artifactInfo, User user, AuditingActionEnum auditingAction, Component parent, + ComponentTypeEnum componentType, ArtifactDefinition currArtifact1, String origMd5, boolean inTransaction) { + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> resultOp = null; + Either<ArtifactDefinition, Operation> insideEither = null; + /* + * currently getArtifactById does not retrieve heatParameters Either<ArtifactDefinition, StorageOperationStatus> artifactRes = artifactOperation.getArtifactById(artifactId, false); ArtifactDefinition currArtifact = artifactRes.left().value(); + */ + Either<ComponentInstance, ResponseFormat> getRI = getRIFromComponent(parent, componentId, artifactId, auditingAction, user); + if (getRI.isRight()) { + return Either.right(getRI.right().value()); + } + ComponentInstance ri = getRI.left().value(); + Either<ArtifactDefinition, ResponseFormat> getArtifactRes = getArtifactFromRI(parent, ri, componentId, artifactId, auditingAction, user); + if (getArtifactRes.isRight()) { + return Either.right(getArtifactRes.right().value()); + } + ArtifactDefinition currArtifact = getArtifactRes.left().value(); + + if (currArtifact.getArtifactType().equals(ArtifactTypeEnum.HEAT.getType()) || currArtifact.getArtifactType().equals(ArtifactTypeEnum.HEAT_VOL.getType()) || currArtifact.getArtifactType().equals(ArtifactTypeEnum.HEAT_NET.getType())) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, ri.getName()); + return Either.right(responseFormat); + } + List<HeatParameterDefinition> currentHeatEnvParams = currArtifact.getHeatParameters(); + List<HeatParameterDefinition> updatedHeatEnvParams = artifactInfo.getHeatParameters(); + List<HeatParameterDefinition> reducedHeatEnvParams = new ArrayList<HeatParameterDefinition>(); + + // upload + if (origMd5 != null) { + Either<List<HeatParameterDefinition>, ResponseFormat> uploadParamsValidationResult = validateUploadParamsFromEnvFile(auditingAction, parent, user, artifactInfo, artifactId, componentType, ri.getName(), currentHeatEnvParams, + updatedHeatEnvParams, currArtifact.getArtifactName()); + if (uploadParamsValidationResult.isRight()) { + ResponseFormat responseFormat = uploadParamsValidationResult.right().value(); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, ri.getName()); + return Either.right(responseFormat); + } + artifactInfo.setHeatParameters(updatedHeatEnvParams); + } + + Either<ArtifactDefinition, ResponseFormat> validateAndConvertHeatParamers = validateAndConvertHeatParamers(artifactInfo, ArtifactTypeEnum.HEAT_ENV.getType()); + if (validateAndConvertHeatParamers.isRight()) { + ResponseFormat responseFormat = validateAndConvertHeatParamers.right().value(); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, ri.getName()); + return Either.right(responseFormat); + } + + if (updatedHeatEnvParams != null && !updatedHeatEnvParams.isEmpty()) { + String paramName; + // fill reduced heat env parameters List for updating + for (HeatParameterDefinition heatEnvParam : updatedHeatEnvParams) { + paramName = heatEnvParam.getName(); + for (HeatParameterDefinition currHeatParam : currentHeatEnvParams) { + if (paramName.equalsIgnoreCase(currHeatParam.getName())) { + String updatedParamValue = heatEnvParam.getCurrentValue(); + if (updatedParamValue != null && updatedParamValue.equals("")) { // reset + heatEnvParam.setCurrentValue(heatEnvParam.getDefaultValue()); + reducedHeatEnvParams.add(heatEnvParam); + } else if (updatedParamValue != null) { + reducedHeatEnvParams.add(heatEnvParam); + } + } + } + } + if (reducedHeatEnvParams.size() > 0) { + ArtifactDefinition reducedArtifactInfo = new ArtifactDefinition(artifactInfo); + reducedArtifactInfo.setHeatParameters(reducedHeatEnvParams); + Either<ArtifactDefinition, StorageOperationStatus> updateArtifactResult = artifactOperation.updateArifactOnResource(reducedArtifactInfo, componentId, artifactInfo.getUniqueId(), componentType.getNodeType(), inTransaction); + + if (updateArtifactResult.isRight()) { + log.debug("Failed to update artifact on graph - {}", artifactId); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateArtifactResult.right().value())); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, ri.getName()); + return Either.right(responseFormat); + } + ArtifactDefinition updatedArtifact = updateArtifactResult.left().value(); + String updatedArtifactId = updatedArtifact.getUniqueId(); + if (!currArtifact.getUniqueId().equals(updatedArtifactId)) { + currArtifact.setUniqueId(updatedArtifactId); + currArtifact.setPayloadUpdateDate(updatedArtifact.getPayloadUpdateDate()); + currArtifact.setCreationDate(updatedArtifact.getCreationDate()); + currArtifact.setLastUpdateDate(updatedArtifact.getLastUpdateDate()); + currArtifact.setEsId(updatedArtifact.getEsId()); + } + currArtifact.setHeatParamsUpdateDate(System.currentTimeMillis()); + + Either<List<HeatParameterDefinition>, StorageOperationStatus> heatParamsForEnv = ((org.openecomp.sdc.be.model.operations.impl.ArtifactOperation) artifactOperation).getHeatParamsForEnv(currArtifact); + if (heatParamsForEnv.isRight()) { + log.debug("failed to get heat parameters values for heat artifact {}", updatedArtifact.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(heatParamsForEnv.right().value())); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, ri.getName()); + return Either.right(responseFormat); + } + List<HeatParameterDefinition> updatedHeatParaetersList = heatParamsForEnv.left().value(); + currArtifact.setHeatParameters(updatedHeatParaetersList); + + Either<ArtifactDefinition, StorageOperationStatus> updateArifactRes = artifactOperation.updateArifactDefinition(currArtifact, true); + if (updateArifactRes.isRight()) { + log.debug("Failed to update artifact on graph - {}", artifactId); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateArifactRes.right().value())); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, ri.getName()); + return Either.right(responseFormat); + } + } + } + + insideEither = Either.left(currArtifact); + resultOp = Either.left(insideEither); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, currArtifact, null, artifactId, responseFormat, componentType, ri.getName()); + return resultOp; + } + + public Either<List<HeatParameterDefinition>, ResponseFormat> validateUploadParamsFromEnvFile(AuditingActionEnum auditingAction, Component parent, User user, ArtifactDefinition artifactInfo, String artifactId, ComponentTypeEnum componentType, + String riName, List<HeatParameterDefinition> currentHeatEnvParams, List<HeatParameterDefinition> updatedHeatEnvParams, String currArtifactName) { + + if (updatedHeatEnvParams == null || updatedHeatEnvParams.isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT, artifactInfo.getArtifactName(), currArtifactName); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, riName); + return Either.right(responseFormat); + } + + for (HeatParameterDefinition uploadedHeatParam : updatedHeatEnvParams) { + String paramName = uploadedHeatParam.getName(); + boolean isExistsInHeat = false; + for (HeatParameterDefinition currHeatParam : currentHeatEnvParams) { + if (paramName.equalsIgnoreCase(currHeatParam.getName())) { + + isExistsInHeat = true; + uploadedHeatParam.setType(currHeatParam.getType()); + uploadedHeatParam.setCurrentValue(uploadedHeatParam.getDefaultValue()); + uploadedHeatParam.setDefaultValue(currHeatParam.getDefaultValue()); + uploadedHeatParam.setUniqueId(currHeatParam.getUniqueId()); + break; + } + } + if (!isExistsInHeat) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISMATCH_HEAT_VS_HEAT_ENV, currArtifactName); + handleAuditing(auditingAction, parent, parent.getUniqueId(), user, artifactInfo, null, artifactId, responseFormat, componentType, riName); + return Either.right(responseFormat); + } + } + return Either.left(updatedHeatEnvParams); + } + + private Either<ComponentInstance, ResponseFormat> getRIFromComponent(Component component, String riID, String artifactId, AuditingActionEnum auditingAction, User user) { + ResponseFormat responseFormat = null; + List<ComponentInstance> ris = component.getComponentInstances(); + for (ComponentInstance ri : ris) { + if (riID.equals(ri.getUniqueId())) { + return Either.left(ri); + } + } + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, riID); + log.debug("Resource Instance not found, resourceInstanceId {}", riID); + handleAuditing(auditingAction, null, riID, user, null, null, artifactId, responseFormat, ComponentTypeEnum.RESOURCE_INSTANCE, null); + return Either.right(responseFormat); + } + + private Either<ArtifactDefinition, ResponseFormat> getArtifactFromRI(Component component, ComponentInstance ri, String riID, String artifactId, AuditingActionEnum auditingAction, User user) { + ResponseFormat responseFormat = null; + Map<String, ArtifactDefinition> rtifactsMap = ri.getDeploymentArtifacts(); + for (ArtifactDefinition artifact : rtifactsMap.values()) { + if (artifactId.equals(artifact.getUniqueId())) { + return Either.left(artifact); + } + } + responseFormat = componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, riID, component.getUniqueId()); + handleAuditing(auditingAction, component, riID, user, null, null, artifactId, responseFormat, ComponentTypeEnum.RESOURCE_INSTANCE, ri.getName()); + return Either.right(responseFormat); + } + + public ComponentOperation getComponentOperation(NodeTypeEnum componentType) { + + switch (componentType) { + case Service: + case ResourceInstance: + return serviceOperation; + case Resource: + return resourceOperation; + default: + return null; + } + } + + public ArtifactDefinition extractArtifactDefinition(Either<ArtifactDefinition, Operation> eitherArtifact) { + ArtifactDefinition ret; + if (eitherArtifact.isLeft()) { + ret = eitherArtifact.left().value(); + } else { + ret = eitherArtifact.right().value().getImplementation(); + } + return ret; + } + + /** + * downloads artifact of component by UUIDs + * + * @param componentType + * @param componentUuid + * @param artifactUUID + * @param auditAdditionalParam + * @return + */ + public Either<byte[], ResponseFormat> downloadComponentArtifactByUUIDs(ComponentTypeEnum componentType, String componentUuid, String artifactUUID, Map<AuditingFieldsKeysEnum, Object> auditAdditionalParam) { + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<byte[], ResponseFormat> result; + byte[] downloadedArtifact = null; + Component component = getLatestComponentByUuid(componentType, componentUuid, errorWrapper); + if (errorWrapper.isEmpty()) { + auditAdditionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, component.getName()); + downloadedArtifact = downloadArtifact(component.getDeploymentArtifacts(), artifactUUID, errorWrapper, component.getName()); + } + if (errorWrapper.isEmpty()) { + result = Either.left(downloadedArtifact); + } else { + result = Either.right(errorWrapper.getInnerElement()); + } + return result; + } + + /** + * downloads an artifact of resource instance of component by UUIDs + * + * @param componentType + * @param componentUuid + * @param resourceName + * @param artifactUUID + * @param auditAdditionalParam + * @return + */ + public Either<byte[], ResponseFormat> downloadResourceInstanceArtifactByUUIDs(ComponentTypeEnum componentType, String componentUuid, String resourceInstanceName, String artifactUUID, Map<AuditingFieldsKeysEnum, Object> auditAdditionalParam) { + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<byte[], ResponseFormat> result; + byte[] downloadedArtifact = null; + ComponentInstance resourceInstance = getRelatedComponentInstance(componentType, componentUuid, resourceInstanceName, errorWrapper); + if (errorWrapper.isEmpty()) { + auditAdditionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInstance.getName()); + downloadedArtifact = downloadArtifact(resourceInstance.getDeploymentArtifacts(), artifactUUID, errorWrapper, resourceInstance.getName()); + } + if (errorWrapper.isEmpty()) { + result = Either.left(downloadedArtifact); + } else { + result = Either.right(errorWrapper.getInnerElement()); + } + return result; + } + + /** + * uploads an artifact to a component by UUID + * + * @param data + * @param request + * @param componentType + * @param componentUuid + * @param additionalParams + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> uploadArtifactToComponentByUUID(String data, HttpServletRequest request, ComponentTypeEnum componentType, String componentUuid, Map<AuditingFieldsKeysEnum, Object> additionalParams) { + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = null; + Either<ArtifactDefinition, ResponseFormat> uploadArtifactResult; + ArtifactDefinition uploadArtifact; + Component component = null; + String componentId = null; + ArtifactOperation operation = ArtifactOperation.Create; + operation.setExternalApi(true); + ArtifactDefinition artifactInfo = RepresentationUtils.convertJsonToArtifactDefinition(data, ArtifactDefinition.class); + String origMd5 = request.getHeader(Constants.MD5_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + + Either<ComponentMetadataData, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentMetadataByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + if (errorWrapper.isEmpty() && !getComponentRes.left().value().getMetadataDataDefinition().getState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + component = checkoutParentComponent(componentType, getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(), userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + if (component != null) { + componentId = component.getUniqueId(); + } else { + componentId = getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(); + } + } + if (errorWrapper.isEmpty()) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, getComponentRes.left().value().getMetadataDataDefinition().getName()); + actionResult = handleArtifactRequest(componentId, userId, componentType, operation, null, artifactInfo, origMd5, data, null, null, null, null); + if (actionResult.isRight()) { + log.debug("Failed to upload artifact to component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, actionResult.right().value()); + errorWrapper.setInnerElement(actionResult.right().value()); + } + } + if (errorWrapper.isEmpty()) { + uploadArtifact = actionResult.left().value().left().value(); + updateAuditParametersWithArtifactDefinition(additionalParams, uploadArtifact); + uploadArtifactResult = Either.left(uploadArtifact); + } else { + uploadArtifactResult = Either.right(errorWrapper.getInnerElement()); + } + return uploadArtifactResult; + } + + /** + * upload an artifact to a resource instance by UUID + * + * @param data + * @param request + * @param componentType + * @param componentUuid + * @param resourceInstanceName + * @param additionalParams + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> uploadArtifactToRiByUUID(String data, HttpServletRequest request, ComponentTypeEnum componentType, String componentUuid, String resourceInstanceName, + Map<AuditingFieldsKeysEnum, Object> additionalParams) { + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactResult; + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = null; + ArtifactDefinition uploadArtifact; + Component component = null; + String componentInstanceId; + String componentId; + String origMd5 = request.getHeader(Constants.MD5_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + + ImmutablePair<Component, ComponentInstance> componentRiPair = null; + Either<ComponentMetadataData, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentMetadataByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + if (errorWrapper.isEmpty() && !getComponentRes.left().value().getMetadataDataDefinition().getState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + component = checkoutParentComponent(componentType, getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(), userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + if (component == null) { + componentRiPair = getRelatedComponentComponentInstance(componentType, componentUuid, resourceInstanceName, errorWrapper); + } else { + componentRiPair = getRelatedComponentComponentInstance(component, resourceInstanceName, errorWrapper); + } + } + if (errorWrapper.isEmpty()) { + componentInstanceId = componentRiPair.getRight().getUniqueId(); + componentId = componentRiPair.getLeft().getUniqueId(); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInstanceName); + ArtifactOperation operation = ArtifactOperation.Create; + operation.setExternalApi(true); + ArtifactDefinition artifactInfo = RepresentationUtils.convertJsonToArtifactDefinition(data, ArtifactDefinition.class); + + actionResult = handleArtifactRequest(componentInstanceId, userId, ComponentTypeEnum.RESOURCE_INSTANCE, operation, null, artifactInfo, origMd5, data, null, null, componentId, ComponentTypeEnum.findParamByType(componentType)); + if (actionResult.isRight()) { + log.debug("Failed to upload artifact to component instance {} of component with type {} and uuid {}. Status is {}. ", resourceInstanceName, componentType, componentUuid, actionResult.right().value()); + errorWrapper.setInnerElement(actionResult.right().value()); + } + } + if (errorWrapper.isEmpty()) { + uploadArtifact = actionResult.left().value().left().value(); + updateAuditParametersWithArtifactDefinition(additionalParams, uploadArtifact); + uploadArtifactResult = Either.left(uploadArtifact); + } else { + uploadArtifactResult = Either.right(errorWrapper.getInnerElement()); + } + return uploadArtifactResult; + } + + /** + * updates an artifact on a component by UUID + * + * @param data + * @param request + * @param componentType + * @param componentUuid + * @param artifactUUID + * @param additionalParams + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> updateArtifactOnComponentByUUID(String data, HttpServletRequest request, ComponentTypeEnum componentType, String componentUuid, String artifactUUID, + Map<AuditingFieldsKeysEnum, Object> additionalParams) { + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<ArtifactDefinition, ResponseFormat> updateArtifactResult; + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = null; + ArtifactDefinition updateArtifact; + Component component = null; + String componentId = null; + String artifactId = null; + ArtifactOperation operation = ArtifactOperation.Update; + operation.setExternalApi(true); + ArtifactDefinition artifactInfo = RepresentationUtils.convertJsonToArtifactDefinition(data, ArtifactDefinition.class); + String origMd5 = request.getHeader(Constants.MD5_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + + Either<ComponentMetadataData, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentMetadataByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + if (errorWrapper.isEmpty() && !getComponentRes.left().value().getMetadataDataDefinition().getState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + component = checkoutParentComponent(componentType, getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(), userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + if (component != null) { + componentId = component.getUniqueId(); + } else { + componentId = getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(); + } + } + if (errorWrapper.isEmpty()) { + artifactId = getLatestParentArtifactDataIdByArtifactUUID(artifactUUID, errorWrapper, componentId, componentType); + } + if (errorWrapper.isEmpty()) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, getComponentRes.left().value().getMetadataDataDefinition().getName()); + + actionResult = handleArtifactRequest(componentId, userId, componentType, operation, artifactId, artifactInfo, origMd5, data, null, null, null, null); + if (actionResult.isRight()) { + log.debug("Failed to upload artifact to component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, actionResult.right().value()); + errorWrapper.setInnerElement(actionResult.right().value()); + } + } + if (errorWrapper.isEmpty()) { + updateArtifact = actionResult.left().value().left().value(); + updateAuditParametersWithArtifactDefinition(additionalParams, updateArtifact); + updateArtifactResult = Either.left(updateArtifact); + + } else { + updateArtifactResult = Either.right(errorWrapper.getInnerElement()); + } + return updateArtifactResult; + } + + /** + * updates an artifact on a resource instance by UUID + * + * @param data + * @param request + * @param componentType + * @param componentUuid + * @param resourceInstanceName + * @param artifactUUID + * @param additionalParams + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> updateArtifactOnRiByUUID(String data, HttpServletRequest request, ComponentTypeEnum componentType, String componentUuid, String resourceInstanceName, String artifactUUID, + Map<AuditingFieldsKeysEnum, Object> additionalParams) { + + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<ArtifactDefinition, ResponseFormat> updateArtifactResult; + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = null; + ArtifactDefinition updateArtifact; + Component component = null; + String componentInstanceId = null; + String componentId = null; + String artifactId = null; + String origMd5 = request.getHeader(Constants.MD5_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + + ImmutablePair<Component, ComponentInstance> componentRiPair = null; + Either<ComponentMetadataData, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentMetadataByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + if (errorWrapper.isEmpty() && !getComponentRes.left().value().getMetadataDataDefinition().getState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + component = checkoutParentComponent(componentType, getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(), userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + if (component == null) { + componentRiPair = getRelatedComponentComponentInstance(componentType, componentUuid, resourceInstanceName, errorWrapper); + } else { + componentRiPair = getRelatedComponentComponentInstance(component, resourceInstanceName, errorWrapper); + } + } + if (errorWrapper.isEmpty()) { + componentInstanceId = componentRiPair.getRight().getUniqueId(); + componentId = componentRiPair.getLeft().getUniqueId(); + artifactId = getLatestParentArtifactDataIdByArtifactUUID(artifactUUID, errorWrapper, componentInstanceId, ComponentTypeEnum.RESOURCE_INSTANCE); + } + if (errorWrapper.isEmpty()) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInstanceName); + ArtifactOperation operation = ArtifactOperation.Update; + operation.setExternalApi(true); + ArtifactDefinition artifactInfo = RepresentationUtils.convertJsonToArtifactDefinition(data, ArtifactDefinition.class); + + actionResult = handleArtifactRequest(componentInstanceId, userId, ComponentTypeEnum.RESOURCE_INSTANCE, operation, artifactId, artifactInfo, origMd5, data, null, null, componentId, ComponentTypeEnum.findParamByType(componentType)); + if (actionResult.isRight()) { + log.debug("Failed to upload artifact to component instance {} of component with type {} and uuid {}. Status is {}. ", resourceInstanceName, componentType, componentUuid, actionResult.right().value()); + errorWrapper.setInnerElement(actionResult.right().value()); + } + } + if (errorWrapper.isEmpty()) { + updateArtifact = actionResult.left().value().left().value(); + updateAuditParametersWithArtifactDefinition(additionalParams, updateArtifact); + updateArtifactResult = Either.left(updateArtifact); + } else { + updateArtifactResult = Either.right(errorWrapper.getInnerElement()); + } + return updateArtifactResult; + + } + + /** + * deletes an artifact on a component by UUID + * + * @param request + * @param componentType + * @param componentUuid + * @param artifactUUID + * @param additionalParams + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> deleteArtifactOnComponentByUUID(HttpServletRequest request, ComponentTypeEnum componentType, String componentUuid, String artifactUUID, Map<AuditingFieldsKeysEnum, Object> additionalParams) { + + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<ArtifactDefinition, ResponseFormat> deleteArtifactResult; + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = null; + ArtifactDefinition deleteArtifact; + Component component = null; + String componentId = null; + String artifactId = null; + ArtifactOperation operation = ArtifactOperation.Delete; + operation.setExternalApi(true); + String origMd5 = request.getHeader(Constants.MD5_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + + Either<ComponentMetadataData, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentMetadataByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + if (errorWrapper.isEmpty() && !getComponentRes.left().value().getMetadataDataDefinition().getState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + component = checkoutParentComponent(componentType, getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(), userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + if (component != null) { + componentId = component.getUniqueId(); + } else { + componentId = getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(); + } + } + if (errorWrapper.isEmpty()) { + artifactId = getLatestParentArtifactDataIdByArtifactUUID(artifactUUID, errorWrapper, componentId, componentType); + } + if (errorWrapper.isEmpty()) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, getComponentRes.left().value().getMetadataDataDefinition().getName()); + + actionResult = handleArtifactRequest(componentId, userId, componentType, operation, artifactId, null, origMd5, null, null, null, null, null); + if (actionResult.isRight()) { + log.debug("Failed to upload artifact to component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, actionResult.right().value()); + errorWrapper.setInnerElement(actionResult.right().value()); + } + } + if (errorWrapper.isEmpty()) { + deleteArtifact = actionResult.left().value().left().value(); + updateAuditParametersWithArtifactDefinition(additionalParams, deleteArtifact); + deleteArtifactResult = Either.left(deleteArtifact); + } else { + deleteArtifactResult = Either.right(errorWrapper.getInnerElement()); + } + return deleteArtifactResult; + } + + /** + * deletes an artifact an a resource instance by UUID + * + * @param request + * @param componentType + * @param componentUuid + * @param resourceInstanceName + * @param artifactUUID + * @param additionalParams + * @return + */ + public Either<ArtifactDefinition, ResponseFormat> deleteArtifactOnRiByUUID(HttpServletRequest request, ComponentTypeEnum componentType, String componentUuid, String resourceInstanceName, String artifactUUID, + Map<AuditingFieldsKeysEnum, Object> additionalParams) { + + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Either<ArtifactDefinition, ResponseFormat> deleteArtifactResult; + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = null; + ArtifactDefinition deleteArtifact; + Component component = null; + String componentInstanceId = null; + String componentId = null; + String artifactId = null; + String origMd5 = request.getHeader(Constants.MD5_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + ImmutablePair<Component, ComponentInstance> componentRiPair = null; + Either<ComponentMetadataData, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentMetadataByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + if (errorWrapper.isEmpty() && !getComponentRes.left().value().getMetadataDataDefinition().getState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + component = checkoutParentComponent(componentType, getComponentRes.left().value().getMetadataDataDefinition().getUniqueId(), userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + if (component == null) { + componentRiPair = getRelatedComponentComponentInstance(componentType, componentUuid, resourceInstanceName, errorWrapper); + } else { + componentRiPair = getRelatedComponentComponentInstance(component, resourceInstanceName, errorWrapper); + } + } + if (errorWrapper.isEmpty()) { + componentInstanceId = componentRiPair.getRight().getUniqueId(); + componentId = componentRiPair.getLeft().getUniqueId(); + artifactId = getLatestParentArtifactDataIdByArtifactUUID(artifactUUID, errorWrapper, componentInstanceId, ComponentTypeEnum.RESOURCE_INSTANCE); + } + if (errorWrapper.isEmpty()) { + + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInstanceName); + ArtifactOperation operation = ArtifactOperation.Delete; + operation.setExternalApi(true); + + actionResult = handleArtifactRequest(componentInstanceId, userId, ComponentTypeEnum.RESOURCE_INSTANCE, operation, artifactId, null, origMd5, null, null, null, componentId, ComponentTypeEnum.findParamByType(componentType)); + + if (actionResult.isRight()) { + log.debug("Failed to upload artifact to component instance {} of component with type {} and uuid {}. Status is {}. ", resourceInstanceName, componentType, componentUuid, actionResult.right().value()); + errorWrapper.setInnerElement(actionResult.right().value()); + } + } + if (errorWrapper.isEmpty()) { + deleteArtifact = actionResult.left().value().left().value(); + updateAuditParametersWithArtifactDefinition(additionalParams, deleteArtifact); + deleteArtifactResult = Either.left(deleteArtifact); + } else { + deleteArtifactResult = Either.right(errorWrapper.getInnerElement()); + } + return deleteArtifactResult; + } + + private ComponentInstance getRelatedComponentInstance(ComponentTypeEnum componentType, String componentUuid, String resourceInstanceName, Wrapper<ResponseFormat> errorWrapper) { + ComponentInstance componentInstance = null; + StorageOperationStatus status; + Either<ComponentInstance, StorageOperationStatus> getResourceInstanceRes = null; + Component component = getLatestComponentByUuid(componentType, componentUuid, errorWrapper); + if (errorWrapper.isEmpty()) { + componentInstance = component.getComponentInstances().stream().filter(ci -> ci.getNormalizedName().equals(resourceInstanceName)).findAny().get(); + if (componentInstance == null) { + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, resourceInstanceName, "resource instance", component.getComponentType().getValue(), component.getName())); + log.debug("Component instance {} was not found for component {}", resourceInstanceName, component.getName()); + } + } + if (errorWrapper.isEmpty()) { + getResourceInstanceRes = resourceInstanceOperation.getResourceInstanceById(componentInstance.getUniqueId()); + if (getResourceInstanceRes.isRight()) { + status = getResourceInstanceRes.right().value(); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } + } + if (errorWrapper.isEmpty()) { + componentInstance = getResourceInstanceRes.left().value(); + getResourceInstanceRes = resourceInstanceOperation.getFullComponentInstance(componentInstance, componentType.getNodeType()); + if (getResourceInstanceRes.isRight()) { + status = getResourceInstanceRes.right().value(); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } else { + componentInstance = getResourceInstanceRes.left().value(); + } + } + return componentInstance; + } + + private ImmutablePair<Component, ComponentInstance> getRelatedComponentComponentInstance(Component component, String resourceInstanceName, Wrapper<ResponseFormat> errorWrapper) { + + ImmutablePair<Component, ComponentInstance> relatedComponentComponentInstancePair = null; + ComponentInstance componentInstance = component.getComponentInstances().stream().filter(ci -> ci.getNormalizedName().equals(resourceInstanceName)).findAny().get(); + if (componentInstance == null) { + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, resourceInstanceName, "resource instance", component.getComponentType().getValue(), component.getName())); + log.debug("Component instance {} was not found for component {}", resourceInstanceName, component.getName()); + } else { + relatedComponentComponentInstancePair = new ImmutablePair<>(component, componentInstance); + } + return relatedComponentComponentInstancePair; + } + + private ImmutablePair<Component, ComponentInstance> getRelatedComponentComponentInstance(ComponentTypeEnum componentType, String componentUuid, String resourceInstanceName, Wrapper<ResponseFormat> errorWrapper) { + ComponentInstance componentInstance; + ImmutablePair<Component, ComponentInstance> relatedComponentComponentInstancePair = null; + Component component = getLatestComponentByUuid(componentType, componentUuid, errorWrapper); + if (errorWrapper.isEmpty()) { + componentInstance = component.getComponentInstances().stream().filter(ci -> ci.getNormalizedName().equals(resourceInstanceName)).findAny().get(); + if (componentInstance == null) { + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, resourceInstanceName, "resource instance", component.getComponentType().getValue(), component.getName())); + log.debug("Component instance {} was not found for component {}", resourceInstanceName, component.getName()); + } else { + relatedComponentComponentInstancePair = new ImmutablePair<>(component, componentInstance); + } + } + return relatedComponentComponentInstancePair; + } + + private byte[] downloadArtifact(Map<String, ArtifactDefinition> artifacts, String artifactUUID, Wrapper<ResponseFormat> errorWrapper, String componentName) { + + byte[] downloadedArtifact = null; + Either<ImmutablePair<String, byte[]>, ResponseFormat> downloadArtifactEither = null; + List<ArtifactDefinition> deploymentArtifacts = null; + ArtifactDefinition deploymentArtifact = null; + if (artifacts != null && !artifacts.isEmpty()) { + deploymentArtifacts = artifacts.values().stream().filter(art -> art.getArtifactUUID() != null && art.getArtifactUUID().equals(artifactUUID)).collect(Collectors.toList()); + } + if (deploymentArtifacts == null || deploymentArtifacts.isEmpty()) { + log.debug("Deployment artifact with uuid {} was not found for component {}", artifactUUID, componentName); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactUUID)); + } + if (errorWrapper.isEmpty()) { + deploymentArtifact = deploymentArtifacts.get(0); + downloadArtifactEither = downloadArtifact(deploymentArtifact); + if (downloadArtifactEither.isRight()) { + log.debug("Failed to download artifact {}. ", deploymentArtifact.getArtifactName()); + errorWrapper.setInnerElement(downloadArtifactEither.right().value()); + } + } + if (errorWrapper.isEmpty()) { + log.trace("Succeeded to download artifact with uniqueId {}", deploymentArtifact.getUniqueId()); + downloadedArtifact = downloadArtifactEither.left().value().getRight(); + } + return downloadedArtifact; + } + + private Component getLatestComponentByUuid(ComponentTypeEnum componentType, String componentUuid, Wrapper<ResponseFormat> errorWrapper) { + Component component = null; + Either<Component, StorageOperationStatus> getComponentRes = getComponentOperation(componentType).getLatestComponentByUuid(componentType.getNodeType(), componentUuid); + if (getComponentRes.isRight()) { + StorageOperationStatus status = getComponentRes.right().value(); + log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); + } else { + component = getComponentRes.left().value(); + } + return component; + } + + private String getLatestParentArtifactDataIdByArtifactUUID(String artifactUUID, Wrapper<ResponseFormat> errorWrapper, String parentId, ComponentTypeEnum componentType) { + String artifactId = null; + ActionStatus actionStatus = ActionStatus.ARTIFACT_NOT_FOUND; + StorageOperationStatus storageStatus; + ArtifactDefinition latestArtifact = null; + List<ArtifactDefinition> artifacts = null; + NodeTypeEnum parentType; + if (componentType.equals(ComponentTypeEnum.RESOURCE)) { + parentType = NodeTypeEnum.Resource; + } else { + parentType = NodeTypeEnum.Service; + } + Either<Map<String, ArtifactDefinition>, StorageOperationStatus> getArtifactsRes = artifactOperation.getArtifacts(parentId, parentType, false); + if (getArtifactsRes.isRight()) { + storageStatus = getArtifactsRes.right().value(); + log.debug("Couldn't fetch artifacts data for parent component {} with uid {}, error: {}", componentType.name(), parentId, storageStatus); + if (!storageStatus.equals(StorageOperationStatus.NOT_FOUND)) { + actionStatus = componentsUtils.convertFromStorageResponse(storageStatus); + } + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(actionStatus, artifactUUID)); + } + if (errorWrapper.isEmpty()) { + artifacts = getArtifactsRes.left().value().values().stream().filter(a -> a.getArtifactUUID() != null && a.getArtifactUUID().equals(artifactUUID)).collect(Collectors.toList()); + if (artifacts == null || artifacts.isEmpty()) { + log.debug("Couldn't fetch artifact with UUID {} data for parent component {} with uid {}, error: {}", artifactUUID, componentType.name(), parentId, actionStatus); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(actionStatus, artifactUUID)); + } + } + if (errorWrapper.isEmpty()) { + latestArtifact = artifacts.stream().max((a1, a2) -> { + int compareRes = Double.compare(Double.parseDouble(a1.getArtifactVersion()), Double.parseDouble(a2.getArtifactVersion())); + if (compareRes == 0) { + compareRes = Long.compare(a1.getLastUpdateDate() == null ? 0 : a1.getLastUpdateDate(), a2.getLastUpdateDate() == null ? 0 : a2.getLastUpdateDate()); + } + return compareRes; + }).get(); + if (latestArtifact == null) { + log.debug("Couldn't fetch latest artifact with UUID {} data for parent component {} with uid {}, error: {}", artifactUUID, componentType.name(), parentId, actionStatus); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(actionStatus, artifactUUID)); + } + } + if (errorWrapper.isEmpty()) { + artifactId = latestArtifact.getUniqueId(); + } + return artifactId; + } + + private Component checkoutParentComponent(ComponentTypeEnum componentType, String parentId, String userId, Wrapper<ResponseFormat> errorWrapper) { + + Component component = null; + Either<User, ActionStatus> getUserRes = userBusinessLogic.getUser(userId, false); + if (getUserRes.isRight()) { + log.debug("Could not fetch User of component {} with uid {} to checked out. Status is {}. ", componentType.getNodeType(), parentId, getUserRes.right().value()); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(getUserRes.right().value())); + } + if (errorWrapper.isEmpty()) { + User modifier = getUserRes.left().value(); + LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction("External API checkout", LifecycleChanceActionEnum.UPDATE_FROM_EXTERNAL_API); + Either<? extends Component, ResponseFormat> checkoutRes = lifecycleBusinessLogic.changeComponentState(componentType, parentId, modifier, LifeCycleTransitionEnum.CHECKOUT, changeInfo, false, true); + if (checkoutRes.isRight()) { + log.debug("Could not change state of component {} with uid {} to checked out. Status is {}. ", componentType.getNodeType(), parentId, checkoutRes.right().value().getStatus()); + errorWrapper.setInnerElement(checkoutRes.right().value()); + } else { + component = checkoutRes.left().value(); + } + } + return component; + } + + private void updateAuditParametersWithArtifactDefinition(Map<AuditingFieldsKeysEnum, Object> additionalParams, ArtifactDefinition artifact) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_CURR_ARTIFACT_UUID, artifact.getArtifactUUID()); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_ARTIFACT_DATA, buildAuditingArtifactData(artifact)); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, artifact.getUpdaterFullName()); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java new file mode 100644 index 0000000000..15fe86da33 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java @@ -0,0 +1,295 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.AttributeDefinition; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.resources.data.AttributeData; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +/** + * This class holds the business logic relevant for attributes manipulation. + * + * @author mshitrit + * + */ +@Component("attributeBusinessLogic") +public class AttributeBusinessLogic extends BaseBusinessLogic { + + private static final String CREATE_ATTRIBUTE = "CreateAttribute"; + private static final String UPDATE_ATTRIBUTE = "UpdateAttribute"; + private static final String DELETE_ATTRIBUTE = "DeleteAttribute"; + + private static Logger log = LoggerFactory.getLogger(AttributeBusinessLogic.class.getName()); + + /** + * Created attribute on the resource with resourceId + * + * @param resourceId + * @param newAttributeDef + * @param userId + * @return AttributeDefinition if created successfully Or ResponseFormat + */ + public Either<AttributeDefinition, ResponseFormat> createAttribute(String resourceId, AttributeDefinition newAttributeDef, String userId) { + Either<AttributeDefinition, ResponseFormat> result = null; + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Attribute", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + if (lockResult != StorageOperationStatus.OK) { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + log.info("Failed to lock component {}. Error - {}", resourceId, lockResult); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + try { + + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Resource resource = status.left().value(); + + // verify that resource is checked-out and the user is the last updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + // verify attribute does not exist in resource + if (isAttributeExist(resource.getAttributes(), resourceId, newAttributeDef.getName())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_ALREADY_EXIST, newAttributeDef.getName())); + } + Either<Map<String, DataTypeDefinition>, ResponseFormat> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache); + if (eitherAllDataTypes.isRight()) { + return Either.right(eitherAllDataTypes.right().value()); + } + // validate property default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newAttributeDef, eitherAllDataTypes.left().value()); + if (defaultValuesValidation.isRight()) { + return Either.right(defaultValuesValidation.right().value()); + } + + handleDefaultValue(newAttributeDef, eitherAllDataTypes.left().value()); + + // add the new attribute to resource on graph + // need to get StorageOpaerationStatus and convert to ActionStatus from + // componentsUtils + Either<AttributeData, StorageOperationStatus> either = attributeOperation.addAttribute(newAttributeDef, resourceId); + if (either.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); + return result; + } + + result = Either.left(attributeOperation.convertAttributeDataToAttributeDefinition(either.left().value(), newAttributeDef.getName(), resourceId)); + return result; + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + + } + + private boolean isAttributeExist(List<AttributeDefinition> attributes, String resourceUid, String propertyName) { + boolean isExist = false; + if (attributes != null) { + isExist = attributes.stream().filter(p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getParentUniqueId(), resourceUid)).findAny().isPresent(); + } + return isExist; + + } + + /** + * @param resourceId + * @param attributeId + * @param userId + * @return + */ + public Either<AttributeDefinition, ResponseFormat> getAttribute(String resourceId, String attributeId, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Attribute", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Resource resource = status.left().value(); + + List<AttributeDefinition> attributes = resource.getAttributes(); + if (attributes == null) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")); + } else { + Either<AttributeDefinition, ResponseFormat> result; + // verify attribute exist in resource + Optional<AttributeDefinition> optionalAtt = attributes.stream().filter(att -> att.getUniqueId().equals(attributeId) && att.getParentUniqueId().equals(resourceId)).findAny(); + + if (optionalAtt.isPresent()) { + result = Either.left(optionalAtt.get()); + } else { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")); + } + return result; + } + + } + + /** + * Updates Attribute on resource + * + * @param resourceId + * @param attributeId + * @param newAttDef + * @param userId + * @return + */ + public Either<AttributeDefinition, ResponseFormat> updateAttribute(String resourceId, String attributeId, AttributeDefinition newAttDef, String userId) { + Either<AttributeDefinition, ResponseFormat> result = null; + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + if (lockResult != StorageOperationStatus.OK) { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(UPDATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + try { + // Get the resource from DB + Either<Resource, StorageOperationStatus> eitherResource = getResource(resourceId); + if (eitherResource.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Resource resource = eitherResource.left().value(); + + // verify that resource is checked-out and the user is the last updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + // verify attribute exist in resource + Either<AttributeDefinition, ResponseFormat> eitherAttribute = getAttribute(resourceId, attributeId, userId); + if (eitherAttribute.isRight()) { + return Either.right(eitherAttribute.right().value()); + } + Either<Map<String, DataTypeDefinition>, ResponseFormat> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache); + if (eitherAllDataTypes.isRight()) { + return Either.right(eitherAllDataTypes.right().value()); + } + + // validate attribute default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newAttDef, eitherAllDataTypes.left().value()); + if (defaultValuesValidation.isRight()) { + return Either.right(defaultValuesValidation.right().value()); + } + // add the new property to resource on graph + Either<AttributeData, StorageOperationStatus> eitherAttUpdate = attributeOperation.updateAttribute(attributeId, newAttDef, eitherAllDataTypes.left().value()); + + if (eitherAttUpdate.isRight()) { + log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, eitherAttUpdate.right().value()); + result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherAttUpdate.right().value()), resource.getName())); + return result; + } + + result = Either.left(attributeOperation.convertAttributeDataToAttributeDefinition(eitherAttUpdate.left().value(), newAttDef.getName(), resourceId)); + return result; + } finally { + commitOrRollback(result); + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + } + + /** + * Deletes Attribute on resource + * + * @param resourceId + * @param attributeId + * @param userId + * @return + */ + public Either<AttributeDefinition, ResponseFormat> deleteAttribute(String resourceId, String attributeId, String userId) { + Either<AttributeDefinition, ResponseFormat> result = null; + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Attribute", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + if (lockResult != StorageOperationStatus.OK) { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(DELETE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + // Get the resource from DB + Either<Resource, StorageOperationStatus> eitherResource = getResource(resourceId); + if (eitherResource.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Resource resource = eitherResource.left().value(); + + // verify that resource is checked-out and the user is the last updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + // verify attribute exist in resource + Either<AttributeDefinition, ResponseFormat> eitherAttributeExist = getAttribute(resourceId, attributeId, userId); + if (eitherAttributeExist.isRight()) { + return Either.right(eitherAttributeExist.right().value()); + } + String attributeName = eitherAttributeExist.left().value().getName(); + + // delete attribute of resource from graph + Either<AttributeData, StorageOperationStatus> eitherAttributeDelete = attributeOperation.deleteAttribute(attributeId); + if (eitherAttributeDelete.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherAttributeDelete.right().value()), resource.getName())); + return result; + } + result = Either.left(attributeOperation.convertAttributeDataToAttributeDefinition(eitherAttributeDelete.left().value(), attributeName, resourceId)); + return result; + } finally { + commitOrRollback(result); + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java new file mode 100644 index 0000000000..93ddff38d5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java @@ -0,0 +1,571 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.IComplexDefaultValue; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; +import org.openecomp.sdc.be.model.operations.api.IArtifactOperation; +import org.openecomp.sdc.be.model.operations.api.IAttributeOperation; +import org.openecomp.sdc.be.model.operations.api.IComponentOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; +import org.openecomp.sdc.be.model.operations.api.IPropertyOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.model.operations.impl.ProductOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.ServiceOperation; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.IUserBusinessLogic; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; + +public abstract class BaseBusinessLogic { + + @Autowired + protected ComponentsUtils componentsUtils; + + @Autowired + protected IUserBusinessLogic userAdmin; + + @Autowired + protected ResourceOperation resourceOperation; + + @Autowired + protected IGraphLockOperation graphLockOperation; + + @Autowired + protected ServiceOperation serviceOperation; + + @Autowired + protected ProductOperation productOperation; + + @Autowired + protected TitanGenericDao titanGenericDao; + + @Autowired + protected IElementOperation elementDao; + + @Autowired + protected IGroupOperation groupOperation; + + @Autowired + protected IGroupTypeOperation groupTypeOperation; + + @Autowired + protected IArtifactOperation artifactOperation; + + @Autowired + protected IAttributeOperation attributeOperation; + + @Autowired + protected IPropertyOperation propertyOperation; + + @Autowired + protected ApplicationDataTypeCache applicationDataTypeCache; + + public void setUserAdmin(UserBusinessLogic userAdmin) { + this.userAdmin = userAdmin; + } + + public void setComponentsUtils(ComponentsUtils componentsUtils) { + this.componentsUtils = componentsUtils; + } + + public void setGraphLockOperation(IGraphLockOperation graphLockOperation) { + this.graphLockOperation = graphLockOperation; + } + + private static Logger log = LoggerFactory.getLogger(BaseBusinessLogic.class.getName()); + + protected Either<User, ResponseFormat> validateUserNotEmpty(User user, String ecompErrorContext) { + String userId = user.getUserId(); + + if (StringUtils.isEmpty(userId)) { + // user.setUserId("UNKNOWN"); + log.debug("User header is missing "); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUserMissingError, ecompErrorContext, user.getUserId()); + BeEcompErrorManager.getInstance().logBeUserMissingError(ecompErrorContext, user.getUserId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + return Either.right(responseFormat); + } + return Either.left(user); + } + + protected Either<User, ResponseFormat> validateUserExists(User user, String ecompErrorContext, boolean inTransaction) { + return validateUserExists(user.getUserId(), ecompErrorContext, inTransaction); + } + + protected void validateUserExist(String userId, String ecompErrorContext, Wrapper<ResponseFormat> errorWrapper) { + Either<User, ResponseFormat> resp = validateUserExists(userId, ecompErrorContext, false); + if (resp.isRight()) { + errorWrapper.setInnerElement(resp.right().value()); + } + } + + public Either<User, ActionStatus> validateUserExistsActionStatus(String userId, String ecompErrorContext) { + Either<User, ActionStatus> eitherCreator = userAdmin.getUser(userId, false); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + if (eitherCreator.right().value().equals(ActionStatus.USER_NOT_FOUND)) { + log.debug("validateUserExists - not authorized user, userId {}", userId); + Either.right(ActionStatus.RESTRICTED_OPERATION); + } else { + log.debug("validateUserExists - failed to authorize user, userId {}", userId); + } + log.debug("User is not listed. userId {}", userId); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUserMissingError, ecompErrorContext, userId); + return Either.right(eitherCreator.right().value()); + } + return Either.left(eitherCreator.left().value()); + } + + public Either<User, ResponseFormat> validateUserExists(String userId, String ecompErrorContext, boolean inTransaction) { + Either<User, ActionStatus> eitherCreator = userAdmin.getUser(userId, inTransaction); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + ResponseFormat responseFormat; + if (eitherCreator.right().value().equals(ActionStatus.USER_NOT_FOUND)) { + if (log.isDebugEnabled()) + log.debug("validateUserExists - not authorized user, userId {}", userId); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + } else { + if (log.isDebugEnabled()) + log.debug("validateUserExists - failed to authorize user, userId {}", userId); + responseFormat = componentsUtils.getResponseFormat(eitherCreator.right().value()); + } + if (log.isDebugEnabled()) + log.debug("User is not listed. userId {}", userId); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUserMissingError, ecompErrorContext, userId); + BeEcompErrorManager.getInstance().logBeUserMissingError(ecompErrorContext, userId); + return Either.right(responseFormat); + } + return Either.left(eitherCreator.left().value()); + } + + protected Either<Boolean, ResponseFormat> validateUserRole(User user, List<Role> roles) { + Role userRole = Role.valueOf(user.getRole()); + if (roles != null) { + if (!roles.contains(userRole)) { + if (log.isDebugEnabled()) + log.debug("user is not in appropriate role to perform action"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + return Either.right(responseFormat); + } + return Either.left(Boolean.TRUE); + } + return Either.left(Boolean.FALSE); + } + + protected Either<Boolean, ResponseFormat> lockComponent(Component component, String ecompErrorContext) { + return lockComponent(component.getUniqueId(), component, ecompErrorContext); + } + + protected Either<Boolean, ResponseFormat> lockComponent(String componentId, Component component, String ecompErrorContext) { + ComponentTypeEnum componentType = component.getComponentType(); + NodeTypeEnum nodeType = componentType.getNodeType(); + StorageOperationStatus lockResourceStatus = graphLockOperation.lockComponent(componentId, nodeType); + + if (lockResourceStatus.equals(StorageOperationStatus.OK)) { + return Either.left(true); + } else { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(ecompErrorContext, nodeType.getName(), componentId); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(lockResourceStatus, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, component.getName()); + log.debug("Failed to lock component {} error - {}", componentId, actionStatus); + return Either.right(responseFormat); + } + } + + protected void unlockComponent(Either<?, ?> either, Component component, boolean inTransaction) { + ComponentTypeEnum componentType = component.getComponentType(); + NodeTypeEnum nodeType = componentType.getNodeType(); + if (false == inTransaction) { + if (either == null || either.isRight()) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + } + // unlock resource + graphLockOperation.unlockComponent(component.getUniqueId(), nodeType); + } + + protected void unlockComponent(Either<?, ?> either, Component component) { + unlockComponent(either, component, false); + } + + protected <T> Either<Boolean, ResponseFormat> validateJsonBody(T bodyObject, Class<T> clazz) { + if (bodyObject == null) { + log.debug("Invalid JSON received for object of type {}", clazz.getSimpleName()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } else { + return Either.left(true); + } + } + + protected Either<ComponentTypeEnum, ResponseFormat> validateComponentType(String componentType) { + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + if (componentTypeEnum == null) { + log.debug("Invalid component type {}", componentType); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, componentType)); + } else { + return Either.left(componentTypeEnum); + } + } + + protected Either<Component, ResponseFormat> validateComponentExists(String componentId, ComponentTypeEnum componentType, boolean inTransaction, boolean createNewTransaction) { + ComponentOperation componentOperation = getComponentOperation(componentType); + Either<Component, StorageOperationStatus> componentFound = null; + // if(createNewTransaction){ + // componentFound = componentOperation.getComponent_tx(componentId, + // inTransaction); + // } + // else{ + componentFound = componentOperation.getComponent(componentId, inTransaction); + // } + + if (componentFound.isRight()) { + StorageOperationStatus storageOperationStatus = componentFound.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, Constants.EMPTY_STRING); + log.debug("Component with id {} was not found", componentId); + return Either.right(responseFormat); + } + return Either.left(componentFound.left().value()); + } + + protected Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists(String componentId, ComponentTypeEnum componentType, ComponentParametersView componentParametersView, String userId, + AuditingActionEnum auditingAction, User user) { + + ComponentOperation componentOperation = getComponentOperation(componentType); + + if (componentOperation == null) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + log.debug("addGroup - not supported component type {}", componentType); + // handleAuditing(auditingAction, null, componentId, user, null, + // null, artifactId, responseFormat, componentType, null); + return Either.right(responseFormat); + } + Either<? extends org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentResult = componentOperation.getComponent(componentId, componentParametersView, true); + + if (componentResult.isRight()) { + ActionStatus status = (componentType.equals(ComponentTypeEnum.RESOURCE)) ? ActionStatus.RESOURCE_NOT_FOUND : ActionStatus.SERVICE_NOT_FOUND; + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(status, componentId); + + log.debug("Service not found, serviceId {}", componentId); + // ComponentTypeEnum componentForAudit = + // (componentType.equals(ComponentTypeEnum.RESOURCE)) ? + // ComponentTypeEnum.RESOURCE : ComponentTypeEnum.SERVICE; + // handleAuditing(auditingAction, null, componentId, user, null, + // null, artifactId, responseFormat, componentForAudit, null); + return Either.right(responseFormat); + } + return Either.left(componentResult.left().value()); + } + + public Either<Boolean, ResponseFormat> validateCanWorkOnComponent(Component component, String userId) { + Either<Boolean, ResponseFormat> canWork = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + if (component.getLifecycleState() != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) { + log.debug("Component {} is not checked-out", component.getName()); + return canWork; + } + + // verify user id is not null + if (userId == null) { + log.debug("Current user userId is null"); + return canWork; + } + + // verify component last update user is the current user + String lastUpdaterUserId = component.getLastUpdaterUserId(); + if (!userId.equals(lastUpdaterUserId)) { + log.debug("Current user is not last updater, last updater userId: {}, current user userId: {}", lastUpdaterUserId, userId); + return canWork; + } + + // verify resource is not deleted + if ((component.getIsDeleted() != null) && (component.getIsDeleted() == true)) { + log.debug("Component {} is marked as deleted", component.getUniqueId()); + return canWork; + } + + return Either.left(true); + } + + public ComponentOperation getComponentOperation(ComponentTypeEnum componentTypeEnum) { + if (ComponentTypeEnum.SERVICE == componentTypeEnum) { + return serviceOperation; + } else if (ComponentTypeEnum.RESOURCE == componentTypeEnum) { + return resourceOperation; + } else if (ComponentTypeEnum.PRODUCT == componentTypeEnum) { + return productOperation; + } + return null; + } + + public IComponentOperation getIComponentOperation(ComponentTypeEnum componentTypeEnum) { + + switch (componentTypeEnum) { + case SERVICE: + return serviceOperation; + case RESOURCE: + return resourceOperation; + case PRODUCT: + return productOperation; + default: + break; + } + + return null; + } + + public ComponentOperation getComponentOperationByParentComponentType(ComponentTypeEnum parentComponentType) { + switch (parentComponentType) { + case SERVICE: + return resourceOperation; + case RESOURCE: + return resourceOperation; + case PRODUCT: + return serviceOperation; + default: + break; + } + return null; + } + + public ComponentTypeEnum getComponentTypeByParentComponentType(ComponentTypeEnum parentComponentType) { + switch (parentComponentType) { + case SERVICE: + return ComponentTypeEnum.RESOURCE; + case RESOURCE: + return ComponentTypeEnum.RESOURCE; + case PRODUCT: + return ComponentTypeEnum.SERVICE; + default: + break; + } + return null; + } + + // For UT + public void setTitanGenericDao(TitanGenericDao titanGenericDao) { + this.titanGenericDao = titanGenericDao; + } + + protected Either<Map<String, DataTypeDefinition>, ResponseFormat> getAllDataTypes(ApplicationDataTypeCache applicationDataTypeCache) { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> allDataTypes = applicationDataTypeCache.getAll(); + if (allDataTypes.isRight()) { + TitanOperationStatus operationStatus = allDataTypes.right().value(); + if (operationStatus == TitanOperationStatus.NOT_FOUND) { + BeEcompErrorManager.getInstance().logInternalDataError("FetchDataTypes", "Data types are not loaded", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPE_CANNOT_BE_EMPTY)); + } else { + BeEcompErrorManager.getInstance().logInternalFlowError("FetchDataTypes", "Failed to fetch data types", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + return Either.left(allDataTypes.left().value()); + } + + protected Either<Boolean, ResponseFormat> validatePropertyDefaultValue(IComplexDefaultValue property, Map<String, DataTypeDefinition> dataTypes) { + log.debug("validate property"); + String type = null; + String innerType = null; + if (!propertyOperation.isPropertyTypeValid(property)) { + log.info("Invalid type for property"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE, property.getType(), property.getName()); + return Either.right(responseFormat); + } + type = property.getType(); + if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) { + ImmutablePair<String, Boolean> propertyInnerTypeValid = propertyOperation.isPropertyInnerTypeValid(property, dataTypes); + innerType = propertyInnerTypeValid.getLeft(); + if (!propertyInnerTypeValid.getRight().booleanValue()) { + log.info("Invalid inner type for property"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE, innerType, property.getName()); + return Either.right(responseFormat); + } + } + if (!propertyOperation.isPropertyDefaultValueValid(property, dataTypes)) { + log.info("Invalid default value for property"); + ResponseFormat responseFormat; + if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE, property.getName(), type, innerType, property.getDefaultValue()); + } else { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEFAULT_VALUE, property.getName(), type, property.getDefaultValue()); + } + return Either.right(responseFormat); + + } + return Either.left(true); + } + + protected Either<Resource, StorageOperationStatus> getResource(final String resourceId) { + + log.debug("Get resource with id {}", resourceId); + Either<Resource, StorageOperationStatus> status = resourceOperation.getResource(resourceId); + if (status.isRight()) { + log.debug("Resource with id {} was not found", resourceId); + return Either.right(status.right().value()); + } + + Resource resource = status.left().value(); + if (resource == null) { + BeEcompErrorManager.getInstance().logBeComponentMissingError("Property Business Logic", ComponentTypeEnum.RESOURCE.getValue(), resourceId); + log.debug("General Error while get resource with id {}", resourceId); + return Either.right(StorageOperationStatus.GENERAL_ERROR); + } + return Either.left(resource); + } + + protected void handleDefaultValue(IComplexDefaultValue newAttributeDef, Map<String, DataTypeDefinition> dataTypes) { + // convert property + ToscaPropertyType type = ToscaPropertyType.isValidType(newAttributeDef.getType()); + PropertyValueConverter converter = type.getConverter(); + // get inner type + String innerType = null; + + if (newAttributeDef != null) { + SchemaDefinition schema = newAttributeDef.getSchema(); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (schema.getProperty() != null) { + innerType = prop.getType(); + } + } + String convertedValue = null; + if (newAttributeDef.getDefaultValue() != null) { + convertedValue = converter.convert(newAttributeDef.getDefaultValue(), innerType, dataTypes); + newAttributeDef.setDefaultValue(convertedValue); + } + } + } + + protected void validateComponentTypeEnum(ComponentTypeEnum componentTypeEnum, String errorContext, Wrapper<ResponseFormat> errorWrapper) { + if (componentTypeEnum == null) { + BeEcompErrorManager.getInstance().logInvalidInputError(errorContext, "invalid component type", ErrorSeverity.INFO); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED)); + } + + } + + protected void validateCanWorkOnComponent(String componentId, ComponentTypeEnum componentTypeEnum, String userId, Wrapper<ResponseFormat> errorWrapper) { + IComponentOperation componentOperation = getIComponentOperation(componentTypeEnum); + if (!ComponentValidationUtils.canWorkOnComponent(componentId, componentOperation, userId)) { + log.info("Restricted operation for user {} on {} {}", userId, componentTypeEnum.getValue(), componentId); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + } + + protected void validateComponentLock(String componentId, ComponentTypeEnum componentTypeEnum, Wrapper<ResponseFormat> errorWrapper) { + StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType()); + if (lockStatus != StorageOperationStatus.OK) { + log.debug("Failed to lock {} {}", componentTypeEnum.getValue(), componentId); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus))); + } + + } + + protected ToscaPropertyType getType(String propertyType) { + + ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType); + + return type; + + } + + protected void commitOrRollback(Either<? extends Object, ResponseFormat> result) { + if (result == null || result.isRight()) { + log.warn("operation failed. do rollback"); + titanGenericDao.rollback(); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + } + + protected Either<Boolean, ResponseFormat> lockComponentByName(String name, Component component, String ecompErrorContext) { + ComponentTypeEnum componentType = component.getComponentType(); + NodeTypeEnum nodeType = componentType.getNodeType(); + StorageOperationStatus lockResourceStatus = graphLockOperation.lockComponentByName(name, nodeType); + + if (lockResourceStatus.equals(StorageOperationStatus.OK)) { + return Either.left(true); + } else { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(ecompErrorContext, nodeType.getName(), name); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(lockResourceStatus, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, component.getName()); + log.debug("Failed to lock component {} error - {}", name, actionStatus); + return Either.right(responseFormat); + } + } + + protected Either<Component, ResponseFormat> validateComponentExistsByFilter(String componentId, ComponentTypeEnum componentType, ComponentParametersView componentParametersView, boolean inTransaction) { + ComponentOperation componentOperation = getComponentOperation(componentType); + Either<Component, StorageOperationStatus> componentFound = null; + componentFound = componentOperation.getComponent(componentId, componentParametersView, inTransaction); + + if (componentFound.isRight()) { + StorageOperationStatus storageOperationStatus = componentFound.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, Constants.EMPTY_STRING); + log.debug("Component with id {} was not found", componentId); + return Either.right(responseFormat); + } + return Either.left(componentFound.left().value()); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilityTypeImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilityTypeImportManager.java new file mode 100644 index 0000000000..5cf42cedd6 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilityTypeImportManager.java @@ -0,0 +1,123 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import javax.annotation.Resource; + +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.CapabilityTypeDefinition; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("capabilityTypeImportManager") +public class CapabilityTypeImportManager { + + private static Logger log = LoggerFactory.getLogger(CapabilityTypeImportManager.class.getName()); + @Resource + private CapabilityTypeOperation capabilityTypeOperation; + @Resource + private ComponentsUtils componentsUtils; + @Resource + private CommonImportManager commonImportManager; + + public Either<List<CapabilityTypeDefinition>, ResponseFormat> createCapabilityTypes(String capabilityYml) { + Either<List<CapabilityTypeDefinition>, ActionStatus> capabilityTypes = createCapabilityTypesFromYml(capabilityYml); + if (capabilityTypes.isRight()) { + ActionStatus status = capabilityTypes.right().value(); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByCapabilityType(status, null); + return Either.right(responseFormat); + } + return createCapabilityTypesByDao(capabilityTypes.left().value()); + + } + + private Either<List<CapabilityTypeDefinition>, ActionStatus> createCapabilityTypesFromYml(String capabilityYml) { + return commonImportManager.createElementTypesFromYml(capabilityYml, (capTypeName, capTypeJsonData) -> createCapabilityType(capTypeName, capTypeJsonData)); + + } + + private Either<List<CapabilityTypeDefinition>, ResponseFormat> createCapabilityTypesByDao(List<CapabilityTypeDefinition> capabilityTypesToCreate) { + List<CapabilityTypeDefinition> createdCapabilities = new ArrayList<>(); + Either<List<CapabilityTypeDefinition>, ResponseFormat> eitherResult = Either.left(createdCapabilities); + Iterator<CapabilityTypeDefinition> capTypeItr = capabilityTypesToCreate.iterator(); + boolean stopDao = false; + while (capTypeItr.hasNext() && !stopDao) { + CapabilityTypeDefinition capabilityType = capTypeItr.next(); + + log.info("send capabilityType {} to dao for create", capabilityType.getType()); + Either<CapabilityTypeDefinition, StorageOperationStatus> dataModelResponse = capabilityTypeOperation.addCapabilityType(capabilityType); + if (dataModelResponse.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedAddingCapabilityTypeError, "Create CapabilityTypes"); + BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("Create CapabilityTypes", "capability type"); + log.debug("failed to create capabilityType: {}", capabilityType.getType()); + if (dataModelResponse.right().value() != StorageOperationStatus.SCHEMA_VIOLATION) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByCapabilityType(componentsUtils.convertFromStorageResponseForCapabilityType(dataModelResponse.right().value()), capabilityType); + eitherResult = Either.right(responseFormat); + stopDao = true; + } + + } else { + createdCapabilities.add(capabilityType); + } + if (!capTypeItr.hasNext()) { + log.info("capabilityTypes were created successfully!!!"); + } + + } + + return eitherResult; + + } + + private CapabilityTypeDefinition createCapabilityType(String capabilityTypeName, Map<String, Object> toscaJson) { + CapabilityTypeDefinition capabilityType = new CapabilityTypeDefinition(); + + capabilityType.setType(capabilityTypeName); + + // Description + final Consumer<String> descriptionSetter = description -> capabilityType.setDescription(description); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DESCRIPTION.getElementName(), descriptionSetter); + // Derived From + final Consumer<String> derivedFromSetter = derivedFrom -> capabilityType.setDerivedFrom(derivedFrom); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DERIVED_FROM.getElementName(), derivedFromSetter); + // Properties + commonImportManager.setPropertiesMap(toscaJson, (values) -> capabilityType.setProperties(values)); + + return capabilityType; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java new file mode 100644 index 0000000000..26ea80ac4b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java @@ -0,0 +1,274 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum; +import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.Yaml; + +import fj.data.Either; + +@Component("categoriesImportManager") +public class CategoriesImportManager { + + @javax.annotation.Resource + private IElementOperation elementOperation; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + private static Logger log = LoggerFactory.getLogger(CategoriesImportManager.class.getName()); + + public Either<Map<String, List<CategoryDefinition>>, ResponseFormat> createCategories(String categoriesTypesYml) { + + Map<String, List<CategoryDefinition>> allCategories = createCategoriesFromYml(categoriesTypesYml); + return createCategoriesByDao(allCategories); + } + + private Either<Map<String, List<CategoryDefinition>>, ResponseFormat> createCategoriesByDao(Map<String, List<CategoryDefinition>> allCategories) { + Map<String, List<CategoryDefinition>> result = new HashMap<>(); + log.debug("createCategoriesByDao: starting to create Categories."); + for (Map.Entry<String, List<CategoryDefinition>> entry : allCategories.entrySet()) { + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(entry.getKey()); + NodeTypeEnum nodeTypeCategory = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentType, CategoryTypeEnum.CATEGORY); + NodeTypeEnum nodeTypeSubCategory = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentType, CategoryTypeEnum.SUBCATEGORY); + NodeTypeEnum nodeTypeGroup = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentType, CategoryTypeEnum.GROUPING); + if (log.isDebugEnabled()) { + log.debug("createCategoriesByDao: creating componentType:{} nodeTypeCategory:{} nodeTypeSubCategory:{} nodeTypeGroup:{}", componentType, nodeTypeCategory, nodeTypeSubCategory, nodeTypeGroup); + } + List<CategoryDefinition> newCategoriesvalue = new ArrayList<>(); + for (CategoryDefinition category : entry.getValue()) { + + Either<CategoryDefinition, ResponseFormat> createdCategoryRes = createCategorieDeo(entry, category, nodeTypeCategory); + if (createdCategoryRes.isRight()) { + return Either.right(createdCategoryRes.right().value()); + } + + CategoryDefinition newcategory = createdCategoryRes.left().value(); + String categoryId = newcategory.getUniqueId(); + log.debug("createCategoriesByDao: create category was successful {}", newcategory); + List<SubCategoryDefinition> newsubcategories = new ArrayList<>(); + List<SubCategoryDefinition> subcategories = category.getSubcategories(); + if (subcategories != null) { + for (SubCategoryDefinition subcategory : subcategories) { + Either<SubCategoryDefinition, ResponseFormat> createdSubCategory = createSubCategorieDeo(entry, newcategory, subcategory, nodeTypeSubCategory); + if (createdSubCategory.isRight()) { + return Either.right(createdCategoryRes.right().value()); + } + SubCategoryDefinition newsubcategory = createdSubCategory.left().value(); + List<GroupingDefinition> groupings = subcategory.getGroupings(); + if (groupings != null) { + List<GroupingDefinition> newgroupings = new ArrayList<>(); + for (GroupingDefinition grouping : groupings) { + Either<GroupingDefinition, ResponseFormat> createdGrouping = createGroupingDeo(entry, grouping, subcategory, category, nodeTypeGroup); + if (createdGrouping.isRight()) { + return Either.right(createdCategoryRes.right().value()); + } + newgroupings.add(createdGrouping.left().value()); + } + newsubcategory.setGroupings(newgroupings); + } + newsubcategories.add(newsubcategory); + } + newcategory.setSubcategories(newsubcategories); + } + newCategoriesvalue.add(newcategory); + } + result.put(entry.getKey(), newCategoriesvalue); + } + return Either.left(result); + } + + private Either<GroupingDefinition, ResponseFormat> createGroupingDeo(Map.Entry<String, List<CategoryDefinition>> entry, GroupingDefinition grouping, SubCategoryDefinition subcategory, CategoryDefinition category, NodeTypeEnum nodeTypeGroup) { + + log.debug("createGroupingDeo: creating grouping {}", grouping); + Either<GroupingDefinition, ActionStatus> createdGrouping = elementOperation.createGrouping(subcategory.getUniqueId(), grouping, nodeTypeGroup); + if (createdGrouping.isRight()) { + if (ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY.equals(createdGrouping.right().value())) { + log.debug(" create grouping for {}. group {} already exists", entry.getKey(), grouping.getName()); + String groupingId = UniqueIdBuilder.buildGroupingUid(grouping.getUniqueId(), grouping.getNormalizedName()); + createdGrouping = elementOperation.getGroupingUniqueForType(nodeTypeGroup, groupingId); + if (createdGrouping.isRight()) { + log.debug("failed to get grouping that exists groupingId: {}, type: {}", groupingId, nodeTypeGroup); + return Either.right(componentsUtils.getResponseFormat(createdGrouping.right().value())); + } + } + log.debug("Failed to create groupingcategory for {}, category {}, subcategory {}, grouping {}, error {}", entry.getKey(), category.getName(), subcategory.getName(), (grouping != null ? grouping.getName() : null), + (createdGrouping != null && createdGrouping.right() != null ? createdGrouping.right().value() : null)); + return Either.right(componentsUtils.getResponseFormat(createdGrouping.right().value())); + } else { + log.debug("createGroupingDeo: create Grouping was successful {}", createdGrouping.left().value()); + } + return Either.left(createdGrouping.left().value()); + + } + + private Either<SubCategoryDefinition, ResponseFormat> createSubCategorieDeo(Map.Entry<String, List<CategoryDefinition>> entry, CategoryDefinition newcategory, SubCategoryDefinition subcategory, NodeTypeEnum nodeTypeSubCategory) { + log.debug("createSubCategorieDeo: creating subcategory {}", subcategory); + Either<SubCategoryDefinition, ActionStatus> createdSubCategory = elementOperation.createSubCategory(newcategory.getUniqueId(), subcategory, nodeTypeSubCategory); + if (createdSubCategory.isRight()) { + if (ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY.equals(createdSubCategory.right().value())) { + log.debug(" create subcategory for {} category {}, alreay exists retrieving", entry.getKey(), newcategory.getName(), subcategory.getName()); + String subCategoryId = UniqueIdBuilder.buildSubCategoryUid(newcategory.getUniqueId(), subcategory.getNormalizedName()); + createdSubCategory = elementOperation.getSubCategory(nodeTypeSubCategory, subCategoryId); + if (createdSubCategory.isRight()) { + log.debug("failed to get sub category that exists subCategoryId: {}, type: {}", subCategoryId, nodeTypeSubCategory); + return Either.right(componentsUtils.getResponseFormat(createdSubCategory.right().value())); + } + } else { + log.debug("Failed to create subcategory for {} category {}, error {}", entry.getKey(), newcategory.getName(), subcategory.getName(), createdSubCategory.right().value()); + return Either.right(componentsUtils.getResponseFormat(createdSubCategory.right().value())); + } + } else { + log.debug("createSubCategorieDeo: create subcategory was successful {}", createdSubCategory.left().value()); + } + return Either.left(createdSubCategory.left().value()); + } + + private Either<CategoryDefinition, ResponseFormat> createCategorieDeo(Map.Entry<String, List<CategoryDefinition>> entry, CategoryDefinition category, NodeTypeEnum nodeTypeCategory) { + log.debug("createCategorieDeo: creating category {}", category); + Either<CategoryDefinition, ActionStatus> createdCategory = elementOperation.createCategory(category, nodeTypeCategory); + if (createdCategory.isRight()) { + log.debug("Failed to create category for {}, error {}", entry.getKey(), category.getName(), createdCategory.right().value()); + if (!ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS.equals(createdCategory.right().value())) { + return Either.right(componentsUtils.getResponseFormat(createdCategory.right().value())); + } else { + log.debug("createCategorieDeo: category exists {} retriving.", category); + String categoryId = UniqueIdBuilder.buildCategoryUid(category.getNormalizedName(), nodeTypeCategory); + createdCategory = elementOperation.getCategory(nodeTypeCategory, categoryId); + if (createdCategory.isRight()) { + log.debug("failed to get category that exists categoryId: {}, type: {}", categoryId, nodeTypeCategory); + return Either.right(componentsUtils.getResponseFormat(createdCategory.right().value())); + } + } + } else { + log.debug("createCategorieDeo: create category was successful {}", createdCategory.left().value()); + } + return Either.left(createdCategory.left().value()); + } + + private Map<String, List<CategoryDefinition>> createCategoriesFromYml(String categoriesTypesYml) { + Map<String, Object> toscaJson = (Map<String, Object>) new Yaml().load(categoriesTypesYml); + Map<String, List<CategoryDefinition>> allCategories = new HashMap<>(); + + Iterator<Entry<String, Object>> categoryEntryItr = toscaJson.entrySet().iterator(); + while (categoryEntryItr.hasNext()) { + Entry<String, Object> categoryTypeEntry = categoryEntryItr.next(); + String categoryType = categoryTypeEntry.getKey(); + List<CategoryDefinition> categoriesPerType = null; + Map<String, Object> categoryPerType = null; + switch (categoryType) { + case ComponentTypeEnum.SERVICE_PARAM_NAME: + categoryPerType = (Map<String, Object>) categoryTypeEntry.getValue(); + categoriesPerType = createServiceCategories(categoryPerType); + break; + case ComponentTypeEnum.RESOURCE_PARAM_NAME: + categoryPerType = (Map<String, Object>) categoryTypeEntry.getValue(); + categoriesPerType = createResourceCategories(categoryPerType); + break; + case ComponentTypeEnum.PRODUCT_PARAM_NAME: + // TODO + break; + default: + log.debug("Not supported category type - {}", categoryType); + break; + } + if (categoriesPerType != null) { + allCategories.put(categoryType, categoriesPerType); + } + } + return allCategories; + } + + private List<CategoryDefinition> createServiceCategories(Map<String, Object> categories) { + List<CategoryDefinition> categroiesDef = new ArrayList<>(); + String catName = null; + List<String> icons = null; + for (Entry<String, Object> entry : categories.entrySet()) { + CategoryDefinition catDef = new CategoryDefinition(); + Map<String, Object> category = (Map<String, Object>) entry.getValue(); + catName = (String) category.get("name"); + catDef.setName(catName); + icons = (List<String>) category.get("icons"); + catDef.setIcons(icons); + String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(catName); + catDef.setNormalizedName(normalizedName); + categroiesDef.add(catDef); + } + + return categroiesDef; + } + + private List<CategoryDefinition> createResourceCategories(Map<String, Object> categoryPerType) { + List<CategoryDefinition> categroiesDef = new ArrayList<>(); + for (Map.Entry<String, Object> entry : categoryPerType.entrySet()) { + Map<String, Object> category = (Map<String, Object>) entry.getValue(); + CategoryDefinition catDef = new CategoryDefinition(); + String catName = (String) category.get("name"); + catDef.setName(catName); + String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(catName); + catDef.setNormalizedName(normalizedName); + Map<String, Object> subcategories = (Map<String, Object>) category.get("subcategories"); + List<SubCategoryDefinition> subcateDef = new ArrayList<>(); + for (Entry<String, Object> subcategory : subcategories.entrySet()) { + Map<String, Object> subcategoryInfo = (Map<String, Object>) subcategory.getValue(); + SubCategoryDefinition subDef = new SubCategoryDefinition(); + String subcategoryName = (String) subcategoryInfo.get("name"); + subDef.setName(subcategoryName); + List<String> subcategoryIcons = (List<String>) subcategoryInfo.get("icons"); + subDef.setIcons(subcategoryIcons); + normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subcategoryName); + subDef.setNormalizedName(normalizedName); + subcateDef.add(subDef); + } + + catDef.setSubcategories(subcateDef); + categroiesDef.add(catDef); + } + return categroiesDef; + } + + public static void setLog(Logger log) { + CategoriesImportManager.log = log; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java new file mode 100644 index 0000000000..9b99b665f7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java @@ -0,0 +1,309 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import jersey.repackaged.com.google.common.base.Function; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.CapabilityTypeDefinition; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GroupTypeDefinition; +import org.openecomp.sdc.be.model.PolicyTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.Yaml; + +import fj.data.Either; + +@Component("commonImportManager") +public class CommonImportManager { + + private static Logger log = LoggerFactory.getLogger(CommonImportManager.class.getName()); + + @Resource + private ComponentsUtils componentsUtils; + @Resource + private PropertyOperation propertyOperation; + + protected void setProperties(Map<String, Object> toscaJson, Consumer<List<PropertyDefinition>> consumer) { + consumer.accept(getProperties(toscaJson)); + } + + private List<PropertyDefinition> getProperties(Map<String, Object> toscaJson) { + List<PropertyDefinition> values = null; + Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(toscaJson); + + if (properties.isLeft()) { + values = new ArrayList<>(); + Map<String, PropertyDefinition> propertiesMap = properties.left().value(); + if (propertiesMap != null && propertiesMap.isEmpty() == false) { + + for (Entry<String, PropertyDefinition> entry : propertiesMap.entrySet()) { + String propName = entry.getKey(); + PropertyDefinition propertyDefinition = entry.getValue(); + PropertyDefinition newPropertyDefinition = new PropertyDefinition(propertyDefinition); + newPropertyDefinition.setName(propName); + values.add(newPropertyDefinition); + } + } + } + + return values; + } + + protected void setPropertiesMap(Map<String, Object> toscaJson, Consumer<Map<String, PropertyDefinition>> consumer) { + final List<PropertyDefinition> properties = getProperties(toscaJson); + if (properties != null) { + Map<String, PropertyDefinition> collect = properties.stream().collect(Collectors.toMap(e -> e.getName(), e -> e)); + consumer.accept(collect); + } + + } + + interface ICreateElementType<T1, T2, ElementType> { + ElementType createElement(T1 firstArg, T2 secondArg); + } + + protected <ElementDefinition> Either<List<ElementDefinition>, ActionStatus> createElementTypesFromYml(String elementTypesYml, ICreateElementType<String, Map<String, Object>, ElementDefinition> createApi) { + + List<ElementDefinition> elementTypes = new ArrayList<>(); + try { + Map<String, Object> toscaJson = (Map<String, Object>) new Yaml().load(elementTypesYml); + + Iterator<Entry<String, Object>> elementTypesEntryItr = toscaJson.entrySet().iterator(); + while (elementTypesEntryItr.hasNext()) { + Entry<String, Object> elementTypeNameDataEntry = elementTypesEntryItr.next(); + String elementTypeName = elementTypeNameDataEntry.getKey(); + Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue(); + ElementDefinition elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData); + elementTypes.add(elementDefinition); + + } + + } catch (Exception e) { + log.debug("Failed to yaml file {} {}", elementTypesYml, e); + return Either.right(ActionStatus.INVALID_YAML_FILE); + } + return Either.left(elementTypes); + } + + protected <FieldType> void setField(Map<String, Object> toscaJson, String fieldName, Consumer<FieldType> setter) { + if (toscaJson.containsKey(fieldName)) { + FieldType fieldValue = (FieldType) toscaJson.get(fieldName); + setter.accept(fieldValue); + } + + } + + enum ElementTypeEnum { + PolicyType, GroupType, DataType, CapabilityType, InterfaceLifecycleType + }; + + private ActionStatus convertFromStorageResponseForElementType(StorageOperationStatus status, ElementTypeEnum elementTypeEnum) { + ActionStatus ret; + switch (elementTypeEnum) { + case GroupType: + ret = componentsUtils.convertFromStorageResponseForGroupType(status); + break; + case DataType: + ret = componentsUtils.convertFromStorageResponseForDataType(status); + break; + case CapabilityType: + ret = componentsUtils.convertFromStorageResponseForCapabilityType(status); + break; + case InterfaceLifecycleType: + ret = componentsUtils.convertFromStorageResponseForLifecycleType(status); + break; + default: + ret = componentsUtils.convertFromStorageResponse(status); + break; + } + return ret; + } + + private <ElementTypeDefinition> ResponseFormat getResponseFormatForElementType(ActionStatus actionStatus, ElementTypeEnum elementTypeEnum, ElementTypeDefinition elementTypeDefinition) { + ResponseFormat ret; + switch (elementTypeEnum) { + case GroupType: + ret = componentsUtils.getResponseFormatByGroupType(actionStatus, (GroupTypeDefinition) elementTypeDefinition); + break; + case PolicyType: + ret = componentsUtils.getResponseFormatByPolicyType(actionStatus, (PolicyTypeDefinition) elementTypeDefinition); + break; + case DataType: + ret = componentsUtils.getResponseFormatByDataType(actionStatus, (DataTypeDefinition) elementTypeDefinition, null); + break; + case CapabilityType: + ret = componentsUtils.getResponseFormatByCapabilityType(actionStatus, (CapabilityTypeDefinition) elementTypeDefinition); + break; + + default: + ret = componentsUtils.getResponseFormat(actionStatus); + break; + } + return ret; + } + + protected <ElementTypeDefinition> Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> createElementTypesByDao(List<ElementTypeDefinition> elementTypesToCreate, + Function<ElementTypeDefinition, Either<ActionStatus, ResponseFormat>> validator, Function<ElementTypeDefinition, ImmutablePair<ElementTypeEnum, String>> elementInfoGetter, + Function<String, Either<ElementTypeDefinition, StorageOperationStatus>> elementFetcher, Function<ElementTypeDefinition, Either<ElementTypeDefinition, StorageOperationStatus>> elementAdder, + BiFunction<ElementTypeDefinition, ElementTypeDefinition, Either<ElementTypeDefinition, StorageOperationStatus>> elementUpgrader) { + + List<ImmutablePair<ElementTypeDefinition, Boolean>> createdElementTypes = new ArrayList<>(); + + Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> eitherResult = Either.left(createdElementTypes); + + Iterator<ElementTypeDefinition> elementTypeItr = elementTypesToCreate.iterator(); + + try { + + while (elementTypeItr.hasNext()) { + ElementTypeDefinition elementType = elementTypeItr.next(); + final ImmutablePair<ElementTypeEnum, String> elementInfo = elementInfoGetter.apply(elementType); + ElementTypeEnum elementTypeEnum = elementInfo.left; + String elementName = elementInfo.right; + + Either<ActionStatus, ResponseFormat> validateElementType = validator.apply(elementType); + if (validateElementType.isRight()) { + ResponseFormat responseFormat = validateElementType.right().value(); + log.debug("Failed in validation of element type {}. Response is {}", elementType, responseFormat.getFormattedMessage()); + eitherResult = Either.right(responseFormat); + break; + } + + log.info("send {} : {} to dao for create", elementTypeEnum.name(), elementName); + + Either<ElementTypeDefinition, StorageOperationStatus> findElementType = elementFetcher.apply(elementName); + if (findElementType.isRight()) { + StorageOperationStatus status = findElementType.right().value(); + log.debug("searched {} finished with result:{}", elementTypeEnum.name(), status.name()); + if (status != StorageOperationStatus.NOT_FOUND) { + ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(status, elementTypeEnum), elementTypeEnum, elementType); + eitherResult = Either.right(responseFormat); + break; + } else { + Either<ElementTypeDefinition, StorageOperationStatus> dataModelResponse = elementAdder.apply(elementType); + + if (dataModelResponse.isRight()) { + try { + BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("Create {}", elementTypeEnum.name()); + log.debug("failed to create {}: {}", elementTypeEnum.name(), elementName); + if (dataModelResponse.right().value() != StorageOperationStatus.SCHEMA_VIOLATION) { + ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(dataModelResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType); + + eitherResult = Either.right(responseFormat); + break; + } else { + createdElementTypes.add(new ImmutablePair<ElementTypeDefinition, Boolean>(elementType, false)); + } + } finally { + propertyOperation.getTitanGenericDao().rollback(); + } + } else { + propertyOperation.getTitanGenericDao().commit(); + createdElementTypes.add(new ImmutablePair<ElementTypeDefinition, Boolean>(elementType, true)); + log.debug("{} : {} was created successfully.", elementTypeEnum.name(), elementName); + } + if (!elementTypeItr.hasNext()) { + log.info("all {} were created successfully!!!", elementTypeEnum.name()); + } + + } + } else { + + if (elementUpgrader != null) { + Either<ElementTypeDefinition, StorageOperationStatus> upgradeResponse = null; + try { + upgradeResponse = elementUpgrader.apply(elementType, findElementType.left().value()); + if (upgradeResponse.isRight()) { + StorageOperationStatus status = upgradeResponse.right().value(); + if (status == StorageOperationStatus.OK) { + createdElementTypes.add(new ImmutablePair<ElementTypeDefinition, Boolean>(elementType, false)); + } else { + ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(upgradeResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType); + eitherResult = Either.right(responseFormat); + break; + } + } else { + log.debug("{} : {} was upgraded successfully.", elementTypeEnum.name(), elementName); + createdElementTypes.add(new ImmutablePair<ElementTypeDefinition, Boolean>(elementType, true)); + } + } finally { + if (upgradeResponse == null || upgradeResponse.isRight()) { + propertyOperation.getTitanGenericDao().rollback(); + } else { + propertyOperation.getTitanGenericDao().commit(); + } + } + + } else { + // mshitrit Once GroupType Versions are supported add + // code here + createdElementTypes.add(new ImmutablePair<ElementTypeDefinition, Boolean>(elementType, false)); + log.debug("{} : {} already exists.", elementTypeEnum.name(), elementName); + } + + } + + } + } finally { + if (eitherResult.isRight()) { + propertyOperation.getTitanGenericDao().rollback(); + } + } + + return eitherResult; + + } + + public <ElementTypeDefinition> Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> createElementTypes(String elementTypesYml, Function<String, Either<List<ElementTypeDefinition>, ActionStatus>> elementTypeFromYmlCreater, + Function<List<ElementTypeDefinition>, Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat>> elementTypeDaoCreater, ElementTypeEnum elementTypeEnum) { + + Either<List<ElementTypeDefinition>, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(elementTypesYml); + if (elementTypes.isRight()) { + ActionStatus status = elementTypes.right().value(); + ResponseFormat responseFormat = getResponseFormatForElementType(status, elementTypeEnum, null); + return Either.right(responseFormat); + } + return elementTypeDaoCreater.apply(elementTypes.left().value()); + + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java new file mode 100644 index 0000000000..6c7b8b9bc7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java @@ -0,0 +1,860 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; +import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ComponentCache; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.resources.data.ComponentMetadataData; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; + +public abstract class ComponentBusinessLogic extends BaseBusinessLogic { + + @Autowired + protected ArtifactsBusinessLogic artifactsBusinessLogic; + + @Autowired + protected ComponentCache componentCache; + + private static Logger log = LoggerFactory.getLogger(ComponentBusinessLogic.class.getName()); + + private static final String TAG_FIELD_LABEL = "tag"; + + public abstract Either<List<String>, ResponseFormat> deleteMarkedComponents(); + + public abstract ComponentInstanceBusinessLogic getComponentInstanceBL(); + + public abstract Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, ComponentTypeEnum componentTypeEnum, String userId, String searchText); + + protected Either<User, ResponseFormat> validateUser(User user, String ecompErrorContext, Component component, AuditingActionEnum auditAction, boolean inTransaction) { + Either<User, ResponseFormat> userValidationResult = validateUserNotEmpty(user, ecompErrorContext); + ResponseFormat responseFormat; + if (userValidationResult.isRight()) { + user.setUserId("UNKNOWN"); + responseFormat = userValidationResult.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", auditAction, component.getComponentType()); + return Either.right(responseFormat); + } + Either<User, ResponseFormat> userResult = validateUserExists(user, ecompErrorContext, inTransaction); + if (userResult.isRight()) { + responseFormat = userResult.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", auditAction, component.getComponentType()); + return Either.right(responseFormat); + } + user = userResult.left().value(); + return userResult; + } + + protected Either<Boolean, ResponseFormat> validateUserRole(User user, Component component, List<Role> roles, AuditingActionEnum auditAction, String comment) { + if (roles != null && roles.isEmpty()) { + roles.add(Role.ADMIN); + roles.add(Role.DESIGNER); + } + Either<Boolean, ResponseFormat> validationResult = validateUserRole(user, roles); + if (validationResult.isRight()) { + ComponentTypeEnum componentType = component.getComponentType(); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + if (componentType.equals(ComponentTypeEnum.SERVICE)) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, comment); + String distributionStatus = ((ServiceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition()).getDistributionStatus(); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DPREV_STATUS, distributionStatus); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DCURR_STATUS, distributionStatus); + } + componentsUtils.auditComponent(validationResult.right().value(), user, component, "", "", auditAction, componentType, additionalParams); + } + return validationResult; + } + + protected Either<Boolean, ResponseFormat> validateComponentName(User user, Component component, AuditingActionEnum actionEnum) { + ComponentTypeEnum type = component.getComponentType(); + String componentName = component.getName(); + if (!ValidationUtils.validateStringNotEmpty(componentName)) { + log.debug("component name is empty"); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, type.getValue()); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + + if (!ValidationUtils.validateComponentNameLength(componentName)) { + log.debug("Component name exceeds max length {} ", ValidationUtils.COMPONENT_NAME_MAX_LENGTH); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT, type.getValue(), "" + ValidationUtils.COMPONENT_NAME_MAX_LENGTH); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + + if (!validateTagPattern(componentName)) { + log.debug("Component name {} has invalid format", componentName); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPONENT_NAME, type.getValue()); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + component.setNormalizedName(ValidationUtils.normaliseComponentName(componentName)); + component.setSystemName(ValidationUtils.convertToSystemName(componentName)); + + return Either.left(true); + } + + protected Either<Boolean, ResponseFormat> validateDescriptionAndCleanup(User user, Component component, AuditingActionEnum actionEnum) { + ComponentTypeEnum type = component.getComponentType(); + String description = component.getDescription(); + if (!ValidationUtils.validateStringNotEmpty(description)) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_DESCRIPTION, type.getValue()); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + + description = ValidationUtils.removeNoneUtf8Chars(description); + description = ValidationUtils.normaliseWhitespace(description); + description = ValidationUtils.stripOctets(description); + description = ValidationUtils.removeHtmlTagsOnly(description); + + Either<Boolean, ResponseFormat> validatDescription = validateComponentDescription(description, type); + if (validatDescription.isRight()) { + ResponseFormat responseFormat = validatDescription.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", actionEnum, type); + return Either.right(responseFormat); + } + component.setDescription(description); + return Either.left(true); + } + + public Either<Boolean, ResponseFormat> validateComponentDescription(String description, ComponentTypeEnum type) { + if (description != null) { + if (!ValidationUtils.validateDescriptionLength(description)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT, type.getValue(), "" + ValidationUtils.COMPONENT_DESCRIPTION_MAX_LENGTH)); + } + + if (!ValidationUtils.validateIsEnglish(description)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_DESCRIPTION, type.getValue())); + } + return Either.left(true); + } + return Either.left(false); + } + + protected Either<Boolean, ResponseFormat> validateComponentNameUnique(User user, Component component, AuditingActionEnum actionEnum) { + ComponentTypeEnum type = component.getComponentType(); + ComponentOperation componentOperation = getComponentOperation(type); + Either<Boolean, StorageOperationStatus> dataModelResponse; + dataModelResponse = componentOperation.validateComponentNameExists(component.getName()); + + if (dataModelResponse.isLeft()) { + if (dataModelResponse.left().value()) { + return Either.left(true); + } else { + log.info("Component with name {} already exists", component.getName()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, type.getValue(), component.getName()); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + } + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "validateComponentNameUnique"); + BeEcompErrorManager.getInstance().logBeSystemError("validateComponentNameUnique"); + log.debug("Error while validateComponentNameUnique for component: {}", component.getName()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + + protected Either<Boolean, ResponseFormat> validateContactId(User user, Component component, AuditingActionEnum actionEnum) { + log.debug("validate component contact info"); + ComponentTypeEnum type = component.getComponentType(); + String contactId = component.getContactId(); + + if (!ValidationUtils.validateStringNotEmpty(contactId)) { + log.info("contact info is missing."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT, type.getValue()); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + + Either<Boolean, ResponseFormat> validateContactIdResponse = validateContactId(contactId, type); + if (validateContactIdResponse.isRight()) { + ResponseFormat responseFormat = validateContactIdResponse.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", actionEnum, type); + } + return validateContactIdResponse; + } + + private Either<Boolean, ResponseFormat> validateContactId(String contactId, ComponentTypeEnum type) { + if (contactId != null) { + if (!ValidationUtils.validateContactId(contactId)) { + log.info("contact info is invalid."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, type.getValue()); + return Either.right(errorResponse); + } + return Either.left(true); + } + return Either.left(false); + } + + protected Either<Boolean, ResponseFormat> validateIcon(User user, Component component, AuditingActionEnum actionEnum) { + log.debug("validate Icon"); + ComponentTypeEnum type = component.getComponentType(); + String icon = component.getIcon(); + if (!ValidationUtils.validateStringNotEmpty(icon)) { + log.info("icon is missing."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_ICON, type.getValue()); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, type); + return Either.right(errorResponse); + } + + Either<Boolean, ResponseFormat> validateIcon = validateIcon(icon, type); + if (validateIcon.isRight()) { + ResponseFormat responseFormat = validateIcon.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", actionEnum, type); + } + return validateIcon; + } + + private Either<Boolean, ResponseFormat> validateIcon(String icon, ComponentTypeEnum type) { + if (icon != null) { + if (!ValidationUtils.validateIconLength(icon)) { + log.debug("icon exceeds max length"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ICON_EXCEEDS_LIMIT, type.getValue(), "" + ValidationUtils.ICON_MAX_LENGTH)); + } + + if (!ValidationUtils.validateIcon(icon)) { + log.info("icon is invalid."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_ICON, type.getValue()); + return Either.right(errorResponse); + } + return Either.left(true); + } + return Either.left(false); + } + + protected Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Component component, AuditingActionEnum actionEnum) { + List<String> tagsList = component.getTags(); + + Either<Boolean, ResponseFormat> validateTags = validateComponentTags(tagsList, component.getName(), component.getComponentType()); + if (validateTags.isRight()) { + ResponseFormat responseFormat = validateTags.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", actionEnum, component.getComponentType()); + return Either.right(responseFormat); + } + ValidationUtils.removeDuplicateFromList(tagsList); + return Either.left(true); + } + + protected Either<Boolean, ResponseFormat> validateComponentTags(List<String> tags, String name, ComponentTypeEnum componentType) { + log.debug("validate component tags"); + boolean includesComponentName = false; + int tagListSize = 0; + if (tags != null && !tags.isEmpty()) { + for (String tag : tags) { + if (!ValidationUtils.validateTagLength(tag)) { + log.debug("tag length exceeds limit {}", ValidationUtils.TAG_MAX_LENGTH); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT, "" + ValidationUtils.TAG_MAX_LENGTH)); + } + if (validateTagPattern(tag)) { + if (!includesComponentName) { + includesComponentName = name.equals(tag); + } + } else { + log.debug("invalid tag {}", tag); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FIELD_FORMAT, componentType.getValue(), TAG_FIELD_LABEL)); + } + tagListSize += tag.length() + 1; + } + if (tagListSize > 0) { + tagListSize--; + } + + if (!includesComponentName) { + log.debug("tags must include component name"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_TAGS_NO_COMP_NAME)); + } + if (!ValidationUtils.validateTagListLength(tagListSize)) { + log.debug("overall tags length exceeds limit {}", ValidationUtils.TAG_LIST_MAX_LENGTH); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_TAGS_EXCEED_LIMIT, "" + ValidationUtils.TAG_LIST_MAX_LENGTH)); + } + return Either.left(true); + } + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_TAGS)); + } + + protected boolean validateTagPattern(String tag) { + return ValidationUtils.validateComponentNamePattern(tag); + } + + protected Either<Boolean, ResponseFormat> validateProjectCode(User user, Component component, AuditingActionEnum actionEnum) { + if (ComponentTypeEnum.RESOURCE.equals(component.getComponentType())) { + return Either.left(true); + } + log.debug("validate PROJECT_CODE name "); + String projectCode = component.getProjectCode(); + + if (!ValidationUtils.validateStringNotEmpty(projectCode)) { + log.info("projectCode is missing."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_PROJECT_CODE); + componentsUtils.auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, component.getComponentType()); + return Either.right(errorResponse); + } + + Either<Boolean, ResponseFormat> validateProjectCodeResponse = validateProjectCode(projectCode); + if (validateProjectCodeResponse.isRight()) { + ResponseFormat responseFormat = validateProjectCodeResponse.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, component, "", "", actionEnum, component.getComponentType()); + } + return validateProjectCodeResponse; + + } + + private Either<Boolean, ResponseFormat> validateProjectCode(String projectCode) { + if (projectCode != null) { + if (!ValidationUtils.validateProjectCode(projectCode)) { + log.info("projectCode is not valid."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROJECT_CODE); + return Either.right(errorResponse); + } + return Either.left(true); + } + return Either.left(false); + } + + protected void checkComponentFieldsForOverrideAttempt(Component component) { + if (component.getLifecycleState() != null) { + log.info("LifecycleState cannot be defined by user. This field will be overridden by the application"); + } + if (component.getVersion() != null) { + log.info("Version cannot be defined by user. This field will be overridden by the application"); + } + if ((component.getCreatorUserId() != null) || (component.getCreatorFullName() != null)) { + log.info("Creator cannot be defined by user. This field will be overridden by the application"); + } + if ((component.getLastUpdaterUserId() != null) || (component.getLastUpdaterFullName() != null)) { + log.info("Last Updater cannot be defined by user. This field will be overridden by the application"); + } + if ((component.getCreationDate() != null)) { + log.info("Creation Date cannot be defined by user. This field will be overridden by the application"); + } + if ((component.isHighestVersion() != null)) { + log.info("Is Highest Version cannot be defined by user. This field will be overridden by the application"); + } + if ((component.getUUID() != null)) { + log.info("UUID cannot be defined by user. This field will be overridden by the application"); + } + if ((component.getLastUpdateDate() != null)) { + log.info("Last Update Date cannot be defined by user. This field will be overridden by the application"); + } + if (component.getUniqueId() != null) { + log.info("uid cannot be defined by user. This field will be overridden by the application."); + component.setUniqueId(null); + } + if (component.getInvariantUUID() != null) { + log.info("Invariant UUID cannot be defined by user. This field will be overridden by the application."); + } + } + + protected Either<Boolean, ResponseFormat> validateComponentFieldsBeforeCreate(User user, Component component, AuditingActionEnum actionEnum) { + // validate component name uniqueness + log.debug("validate component name "); + Either<Boolean, ResponseFormat> componentNameValidation = validateComponentName(user, component, actionEnum); + if (componentNameValidation.isRight()) { + return componentNameValidation; + } + + // validate description + log.debug("validate description"); + Either<Boolean, ResponseFormat> descValidation = validateDescriptionAndCleanup(user, component, actionEnum); + if (descValidation.isRight()) { + return descValidation; + } + + // validate tags + log.debug("validate tags"); + Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, component, actionEnum); + if (tagsValidation.isRight()) { + return tagsValidation; + } + + // validate contact info + log.debug("validate contact info"); + Either<Boolean, ResponseFormat> contactIdValidation = validateContactId(user, component, actionEnum); + if (contactIdValidation.isRight()) { + return contactIdValidation; + } + + // validate icon + log.debug("validate icon"); + Either<Boolean, ResponseFormat> iconValidation = validateIcon(user, component, actionEnum); + if (iconValidation.isRight()) { + return iconValidation; + } + return Either.left(true); + } + + /*** + * Fetches Component From the DB + * + * @param componentId + * @param componentTypeEnum + * @return + */ + public <R extends Component> Either<R, StorageOperationStatus> getComponent(String componentId, ComponentTypeEnum componentTypeEnum) { + ComponentOperation componentOperation = getComponentOperation(componentTypeEnum); + Either<R, StorageOperationStatus> eitherComponent = componentOperation.getComponent(componentId, false); + return eitherComponent; + } + + public Either<CapReqDef, ResponseFormat> getRequirementsAndCapabilities(String componentId, ComponentTypeEnum componentTypeEnum, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Component Instance", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Map<String, List<CapabilityDefinition>> capabilities = new HashMap<>(); + Map<String, List<RequirementDefinition>> requirements = new HashMap<>(); + Either<CapReqDef, ResponseFormat> eitherRet; + ComponentOperation componentOperation = getComponentOperation(componentTypeEnum); + Either<Component, ResponseFormat> eitherComponent = validateComponentExists(componentId, componentTypeEnum, false, true); + if (eitherComponent.isLeft()) { + Either<Map<String, List<CapabilityDefinition>>, TitanOperationStatus> eitherCapabilities = componentOperation.getCapabilities(eitherComponent.left().value(), componentTypeEnum.getNodeType(), false); + if (eitherCapabilities.isRight()) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + eitherRet = Either.right(errorResponse); + } else { + Either<Map<String, List<RequirementDefinition>>, TitanOperationStatus> eitherRequirements = componentOperation.getRequirements(eitherComponent.left().value(), componentTypeEnum.getNodeType(), false); + if (eitherRequirements.isRight()) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + eitherRet = Either.right(errorResponse); + } else { + requirements = eitherRequirements.left().value(); + capabilities = eitherCapabilities.left().value(); + eitherRet = Either.left(new CapReqDef(requirements, capabilities)); + } + } + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeResourceMissingError, "getRequirementsAndCapabilities", componentId); + BeEcompErrorManager.getInstance().logBeComponentMissingError("getRequirementsAndCapabilities", componentTypeEnum.getValue(), componentId); + eitherRet = Either.right(eitherComponent.right().value()); + } + + return eitherRet; + } + + public Either<List<Component>, ResponseFormat> getLatestVersionNotAbstractComponents(boolean isAbstractAbstract, HighestFilterEnum highestFilter, ComponentTypeEnum componentTypeEnum, String internalComponentType, List<String> componentUids, + String userId) { + + long startUser = System.currentTimeMillis(); + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Latest Version Not Abstract Components", false); + long endUser = System.currentTimeMillis(); + log.debug("Activation time of get user {} ms", (endUser - startUser)); + ResponseFormat responseFormat; + if (resp.isLeft()) { + + List<Component> result = new ArrayList<Component>(); + Set<String> nonProcessesComponents = new HashSet<>(); + nonProcessesComponents.addAll(componentUids); + + long startGetComp = System.currentTimeMillis(); + // Read components from cache + Set<String> filteredComponents = new HashSet<>(); + filteredComponents.addAll(componentUids); + + Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> allPartialComponents = componentCache.getComponentsForLeftPanel(componentTypeEnum, internalComponentType, filteredComponents); + + if (allPartialComponents.isRight()) { + log.debug("Components was not fetched from cache. Status is {}", allPartialComponents.right().value()); + } else { + ImmutableTriple<List<Component>, List<Component>, Set<String>> immutableTriple = allPartialComponents.left().value(); + List<Component> processedComponents = immutableTriple.left; + if (processedComponents != null) { + result.addAll(processedComponents); + } + List<Component> dirtyComponents = immutableTriple.middle; + if (dirtyComponents != null) { + result.addAll(dirtyComponents); + } + + Set<String> nonProcessesComponentsFromCache = immutableTriple.right; + nonProcessesComponents = nonProcessesComponentsFromCache; + } + long endGetComp = System.currentTimeMillis(); + log.debug("Activation time of get Comp from cache {} ms", (endGetComp - startGetComp)); + + // Fecth non cached components + List<String> componentsUidToFetch = new ArrayList<String>(); + componentsUidToFetch.addAll(nonProcessesComponents); + + long startGetCompFromGraph = System.currentTimeMillis(); + if (componentsUidToFetch.size() > 0) { + log.debug("Number of Components to fetch from graph is {}", componentsUidToFetch.size()); + ComponentOperation componentOperation = getComponentOperation(componentTypeEnum); + Boolean isHighest = isHighest(highestFilter); + Either<List<Component>, StorageOperationStatus> nonCheckoutCompResponse = componentOperation.getLatestVersionNotAbstractComponents(isAbstractAbstract, isHighest, componentTypeEnum, internalComponentType, componentsUidToFetch); + + if (nonCheckoutCompResponse.isLeft()) { + log.debug("Retrived Resource successfully."); + result.addAll(nonCheckoutCompResponse.left().value()); + } else { + responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(nonCheckoutCompResponse.right().value())); + } + } + long endGetCompFromGraph = System.currentTimeMillis(); + log.debug("Activation time of get Comp from graph {} ms", (endGetCompFromGraph - startGetCompFromGraph)); + + return Either.left(result); + } else { + responseFormat = resp.right().value(); + } + + return Either.right(responseFormat); + } + + private Boolean isHighest(HighestFilterEnum highestFilter) { + Boolean isHighest = null; + switch (highestFilter) { + case ALL: + break; + case HIGHEST_ONLY: + isHighest = true; + break; + case NON_HIGHEST_ONLY: + isHighest = false; + break; + default: + break; + } + return isHighest; + } + + public Either<List<Map<String, String>>, ResponseFormat> getLatestVersionNotAbstractComponentsUidOnly(boolean isAbstractAbstract, HighestFilterEnum highestFilter, ComponentTypeEnum componentTypeEnum, String internalComponentType, String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Latest Version Not Abstract Components", false); + ResponseFormat responseFormat; + if (resp.isLeft()) { + + ComponentOperation componentOperation = getComponentOperation(componentTypeEnum); + Boolean isHighest = isHighest(highestFilter); + Either<Collection<ComponentMetadataData>, StorageOperationStatus> nonCheckoutCompResponse = componentOperation.getLatestVersionNotAbstractComponentsMetadataOnly(isAbstractAbstract, isHighest, componentTypeEnum, internalComponentType); + + if (nonCheckoutCompResponse.isLeft()) { + log.debug("Retrived Resource successfully."); + List<Map<String, String>> res = new ArrayList<>(); + + // Map<String,String>resMap = + // nonCheckoutCompResponse.left().value().stream().collect() + // .collect(Collectors.toMap( + // p -> p.getMetadataDataDefinition().getUniqueId(), + // p-> p.getMetadataDataDefinition().getVersion())); + + res = nonCheckoutCompResponse.left().value().stream().map(p -> { + HashMap<String, String> map = new HashMap<>(); + map.put("uid", p.getMetadataDataDefinition().getUniqueId()); + map.put("version", p.getMetadataDataDefinition().getVersion()); + Long lastUpdateDate = p.getMetadataDataDefinition().getLastUpdateDate(); + String lastUpdateDateStr = lastUpdateDate != null ? String.valueOf(lastUpdateDate.longValue()) : "0"; + map.put("timestamp", lastUpdateDateStr); + return map; + }).collect(Collectors.toList()); + + return Either.left(res); + } + responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(nonCheckoutCompResponse.right().value())); + } else { + responseFormat = resp.right().value(); + } + + return Either.right(responseFormat); + } + + public void setDeploymentArtifactsPlaceHolder(Component component, User user) { + + } + + public void setToscaArtifactsPlaceHolders(Component component, User user) { + Map<String, ArtifactDefinition> artifactMap = component.getToscaArtifacts(); + if (artifactMap == null) { + artifactMap = new HashMap<String, ArtifactDefinition>(); + } + String componentUniqueId = component.getUniqueId(); + String componentSystemName = component.getSystemName(); + String componentType = component.getComponentType().getValue().toLowerCase(); + Map<String, Object> toscaArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaArtifacts(); + + if (toscaArtifacts != null) { + for (Entry<String, Object> artifactInfoMap : toscaArtifacts.entrySet()) { + Map<String, Object> artifactInfo = (Map<String, Object>) artifactInfoMap.getValue(); + ArtifactDefinition artifactDefinition = artifactsBusinessLogic.createArtifactPlaceHolderInfo(componentUniqueId, artifactInfoMap.getKey(), artifactInfo, user, ArtifactGroupTypeEnum.TOSCA); + artifactDefinition.setArtifactName(componentType + "-" + componentSystemName + artifactInfo.get("artifactName")); + artifactMap.put(artifactDefinition.getArtifactLabel(), artifactDefinition); + } + } + component.setToscaArtifacts(artifactMap); + } + + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> populateToscaArtifacts(Component component, User user, boolean isInCertificationRequest, boolean inTransaction, boolean shouldLock) { + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> generateToscaRes = null; + if (component.getToscaArtifacts() != null && !component.getToscaArtifacts().isEmpty()) { + ArtifactDefinition toscaArtifact = component.getToscaArtifacts().values().stream().filter(p -> p.getArtifactType().equals(ArtifactTypeEnum.TOSCA_TEMPLATE.getType())).findAny().get(); + generateToscaRes = saveToscaArtifactPayload(toscaArtifact, component, user, isInCertificationRequest, shouldLock, inTransaction, true); + if (generateToscaRes.isRight()) { + return generateToscaRes; + } + toscaArtifact = component.getToscaArtifacts().values().stream().filter(p -> p.getArtifactType().equals(ArtifactTypeEnum.TOSCA_CSAR.getType())).findAny().get(); + generateToscaRes = saveToscaArtifactPayload(toscaArtifact, component, user, isInCertificationRequest, shouldLock, inTransaction, true); + } + // TODO if csar artifact fails delete template artifact + return generateToscaRes; + } + + public Either<Either<ArtifactDefinition, Operation>, ResponseFormat> saveToscaArtifactPayload(ArtifactDefinition artifactDefinition, org.openecomp.sdc.be.model.Component component, User user, boolean isInCertificationRequest, boolean shouldLock, + boolean inTransaction, boolean fetchTemplatesFromDB) { + return artifactsBusinessLogic.generateAndSaveToscaArtifact(artifactDefinition, component, user, isInCertificationRequest, shouldLock, inTransaction, fetchTemplatesFromDB); + } + + public Either<ImmutablePair<String, byte[]>, ResponseFormat> getToscaModelByComponentUuid(ComponentTypeEnum componentType, String uuid, EnumMap<AuditingFieldsKeysEnum, Object> additionalParam) { + // get info + ComponentOperation componentOperation = getComponentOperation(componentType); + Either<Component, StorageOperationStatus> latestVersion = componentOperation.getLatestComponentByUuid(componentType.getNodeType(), uuid); + if (latestVersion.isRight()) { + ResponseFormat response = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(latestVersion.right().value(), componentType)); + return Either.right(response); + + } + Component component = latestVersion.left().value(); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, component.getName()); + // TODO remove after migration - handle artifact not found(no + // placeholder) + if (null == component.getToscaArtifacts() || component.getToscaArtifacts().isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, ArtifactTypeEnum.TOSCA_CSAR.name())); + } + ArtifactDefinition csarArtifact = component.getToscaArtifacts().values().stream().filter(p -> p.getArtifactType().equals(ArtifactTypeEnum.TOSCA_CSAR.getType())).findAny().get(); + return artifactsBusinessLogic.handleDownloadToscaModelRequest(component, csarArtifact, true, false); + } + + protected StorageOperationStatus markComponentToDelete(Component component) { + + ComponentTypeEnum componentType = component.getComponentType(); + String uniqueId = component.getUniqueId(); + if ((component.getIsDeleted() != null) && (component.getIsDeleted() == true)) { + log.info("component {} already marked as deleted. id= {}, type={}", component.getName(), uniqueId, componentType); + return StorageOperationStatus.NOT_FOUND; + } + + ComponentOperation componentOperation = getComponentOperation(componentType); + + Either<Component, StorageOperationStatus> markResourceToDelete = componentOperation.markComponentToDelete(component, true); + if (markResourceToDelete.isRight()) { + StorageOperationStatus result = markResourceToDelete.right().value(); + log.debug("failed to mark component {} of type {} for delete. error = {}", uniqueId, componentType, result); + return result; + } else { + log.debug("Component {} of type {} was marked as deleted", uniqueId, componentType); + return StorageOperationStatus.OK; + } + } + + public Either<Boolean, ResponseFormat> validateAndUpdateDescription(User user, Component currentComponent, Component updatedComponent, AuditingActionEnum audatingAction) { + String descriptionUpdated = updatedComponent.getDescription(); + String descriptionCurrent = currentComponent.getDescription(); + if (descriptionUpdated != null && !descriptionCurrent.equals(descriptionUpdated)) { + Either<Boolean, ResponseFormat> validateDescriptionResponse = validateDescriptionAndCleanup(user, updatedComponent, audatingAction); + if (validateDescriptionResponse.isRight()) { + ResponseFormat errorRespons = validateDescriptionResponse.right().value(); + return Either.right(errorRespons); + } + currentComponent.setDescription(updatedComponent.getDescription()); + } + return Either.left(true); + } + + public Either<Boolean, ResponseFormat> validateAndUpdateProjectCode(User user, Component currentComponent, Component updatedComponent) { + String projectCodeUpdated = updatedComponent.getProjectCode(); + String projectCodeCurrent = currentComponent.getProjectCode(); + if (projectCodeUpdated != null && !projectCodeCurrent.equals(projectCodeUpdated)) { + Either<Boolean, ResponseFormat> validatProjectCodeResponse = validateProjectCode(user, updatedComponent, null); + if (validatProjectCodeResponse.isRight()) { + ResponseFormat errorRespons = validatProjectCodeResponse.right().value(); + return Either.right(errorRespons); + } + currentComponent.setProjectCode(updatedComponent.getProjectCode()); + } + return Either.left(true); + } + + public Either<Boolean, ResponseFormat> validateAndUpdateIcon(User user, Component currentComponent, Component updatedComponent, boolean hasBeenCertified) { + String iconUpdated = updatedComponent.getIcon(); + String iconCurrent = currentComponent.getIcon(); + if (iconUpdated != null && !iconCurrent.equals(iconUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validatIconResponse = validateIcon(user, updatedComponent, null); + if (validatIconResponse.isRight()) { + ResponseFormat errorRespons = validatIconResponse.right().value(); + return Either.right(errorRespons); + } + currentComponent.setIcon(updatedComponent.getIcon()); + } else { + log.info("icon {} cannot be updated once the component has been certified once.", iconUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_PARAMETER_CANNOT_BE_CHANGED, "Icon", currentComponent.getComponentType().name().toLowerCase()); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + protected Either<List<String>, ResponseFormat> deleteMarkedComponents(ComponentTypeEnum componentType) { + + List<String> deletedComponents = new ArrayList<String>(); + log.trace("start deleteMarkedComponents"); + ComponentOperation componentOperation = getComponentOperation(componentType); + Either<List<String>, StorageOperationStatus> resourcesToDelete = componentOperation.getAllComponentsMarkedForDeletion(); + if (resourcesToDelete.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resourcesToDelete.right().value(), componentType)); + return Either.right(responseFormat); + } + + for (String resourceToDelete : resourcesToDelete.left().value()) { + + Either<String, ResponseFormat> deleteMarkedResource = deleteMarkedComponent(resourceToDelete, componentType); + if (deleteMarkedResource.isLeft()) { + deletedComponents.add(deleteMarkedResource.left().value()); + } + } + + log.trace("end deleteMarkedComponents"); + return Either.left(deletedComponents); + } + + private Either<String, ResponseFormat> deleteMarkedComponent(String componentToDelete, ComponentTypeEnum componentType) { + + Either<String, ResponseFormat> result = null; + ComponentOperation componentOperation = getComponentOperation(componentType); + NodeTypeEnum compNodeType = componentType.getNodeType(); + StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentToDelete, compNodeType); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedLockObjectError, "Delete marked component"); + log.debug("Failed to lock component {}. error - {}", componentToDelete, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + try { + + // check if resource has relations + Either<Boolean, StorageOperationStatus> isResourceInUse = componentOperation.isComponentInUse(componentToDelete); + if (isResourceInUse.isRight()) { + log.info("deleteMarkedResource - failed to find relations to resource. id = {}, type = {}, error = {}", componentToDelete, componentType, isResourceInUse.right().value().name()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + result = Either.right(responseFormat); + return result; + } + + if (isResourceInUse.isLeft() && isResourceInUse.left().value() == false) { + + // delete resource and its artifacts in one transaction + Either<List<ArtifactDefinition>, StorageOperationStatus> artifactsRes = componentOperation.getComponentArtifactsForDelete(componentToDelete, compNodeType, true); + if (artifactsRes.isRight() && !artifactsRes.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + log.info("failed to check artifacts for component node. id = {}, type = {}, error = {}", componentToDelete, componentType, artifactsRes.right().value().name()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + result = Either.right(responseFormat); + return result; + } + List<ArtifactDefinition> artifactsToDelete = new ArrayList<>(); + if (artifactsRes.isLeft()) { + artifactsToDelete = artifactsRes.left().value(); + } + + Either<Component, StorageOperationStatus> deleteComponentRes = componentOperation.deleteComponent(componentToDelete, true); + if (deleteComponentRes.isRight()) { + log.info("failed to delete component. id = {}, type = {}, error = {}", componentToDelete, componentType, deleteComponentRes.right().value().name()); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(deleteComponentRes.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, componentToDelete); + result = Either.right(responseFormat); + } else { + log.trace("component was deleted, id = {}, type = {}", componentToDelete, componentType); + // delete related artifacts + StorageOperationStatus deleteFromEsRes = artifactsBusinessLogic.deleteAllComponentArtifactsIfNotOnGraph(artifactsToDelete); + if (!deleteFromEsRes.equals(StorageOperationStatus.OK)) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(deleteFromEsRes); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, componentToDelete); + result = Either.right(responseFormat); + return result; + } + log.debug("component and all its artifacts were deleted, id = {}, type = {}", componentToDelete, componentType); + result = Either.left(componentToDelete); + } + } else { + // resource in use + log.debug("componentis marked for delete but still in use, id = {}, type = {}", componentToDelete, componentType); + ActionStatus actionStatus = ActionStatus.RESTRICTED_OPERATION; + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, componentToDelete); + result = Either.right(responseFormat); + return result; + } + } finally { + if (result == null || result.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "delete marked component"); + log.debug("operation failed. do rollback"); + titanGenericDao.rollback(); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + graphLockOperation.unlockComponent(componentToDelete, compNodeType); + } + + return result; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java new file mode 100644 index 0000000000..89ef6f7e19 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -0,0 +1,1661 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.info.CreateAndAssotiateInfo; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceAttribute; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.IComponentInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IComponentOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.model.operations.impl.GroupOperation; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; + +public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { + + private static final String ARTIFACT_PLACEHOLDER_FILE_EXTENSION = "fileExtension"; + + static final String HEAT_ENV_NAME = "heatEnv"; + private static final String HEAT_ENV_SUFFIX = "env"; + + private static Logger log = LoggerFactory.getLogger(ComponentInstanceBusinessLogic.class.getName()); + + @Autowired + private IComponentInstanceOperation componentInstanceOperation; + + @Autowired + private PropertyOperation propertyOperation; + + @Autowired + private ArtifactsBusinessLogic artifactBusinessLogic; + + @Autowired + private GroupOperation groupOperation; + + public ComponentInstanceBusinessLogic() { + } + + public Either<ComponentInstance, ResponseFormat> createComponentInstance(String containerComponentParam, String containerComponentId, String userId, ComponentInstance resourceInstance) { + return createComponentInstance(containerComponentParam, containerComponentId, userId, resourceInstance, true, true, true); + } + + public Either<ComponentInstance, ResponseFormat> createComponentInstance(String containerComponentParam, String containerComponentId, String userId, ComponentInstance resourceInstance, boolean inTransaction, boolean needLock, + boolean createNewTransaction) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Component Instance", inTransaction); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<Boolean, ResponseFormat> validateValidJson = validateJsonBody(resourceInstance, ComponentInstance.class); + if (validateValidJson.isRight()) { + return Either.right(validateValidJson.right().value()); + } + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + final ComponentOperation containerOperation = getComponentOperation(containerComponentType); + + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(containerComponentId, containerComponentType, inTransaction, createNewTransaction); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateAllowedToContainCompInstances = validateAllowedToContainCompInstances(containerComponent); + if (validateAllowedToContainCompInstances.isRight()) { + return Either.right(validateAllowedToContainCompInstances.right().value()); + } + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + if (resourceInstance != null && containerComponentType != null) { + Either<Boolean, ResponseFormat> validateComponentInstanceParentState = validateComponentInstanceParentState(containerComponentType, resourceInstance); + if (validateComponentInstanceParentState.isRight()) { + return Either.right(validateComponentInstanceParentState.right().value()); + } + } + if (needLock) { + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "createComponentInstance"); + + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + Either<ComponentInstance, ResponseFormat> resultOp = null; + try { + log.debug("Try to create entry on graph"); + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(resourceInstance, inTransaction); + + if (eitherResourceName.isRight()) { + resultOp = Either.right(eitherResourceName.right().value()); + return resultOp; + } + Component origComponent = eitherResourceName.left().value(); + + resultOp = createComponentInstanceOnGraph(containerComponent, origComponent, resourceInstance, userId, containerOperation, inTransaction); + return resultOp; + + } finally { + if (needLock) + unlockComponent(resultOp, containerComponent); + } + } + + public Either<CreateAndAssotiateInfo, ResponseFormat> createAndAssociateRIToRI(String containerComponentParam, String containerComponentId, String userId, CreateAndAssotiateInfo createAndAssotiateInfo) { + + Either<CreateAndAssotiateInfo, ResponseFormat> resultOp = null; + ComponentInstance resourceInstance = createAndAssotiateInfo.getNode(); + RequirementCapabilityRelDef associationInfo = createAndAssotiateInfo.getAssociate(); + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create And Associate RI To RI", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + final ComponentOperation containerOperation = getComponentOperation(containerComponentType); + + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(containerComponentId, containerComponentType, false, true); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateAllowedToContainCompInstances = validateAllowedToContainCompInstances(containerComponent); + if (validateAllowedToContainCompInstances.isRight()) { + return Either.right(validateAllowedToContainCompInstances.right().value()); + } + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "createAndAssociateRIToRI"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + + try { + log.debug("Try to create entry on graph"); + NodeTypeEnum containerNodeType = containerComponentType.getNodeType(); + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(resourceInstance, true); + + if (eitherResourceName.isRight()) { + resultOp = Either.right(eitherResourceName.right().value()); + return resultOp; + } + Component origComponent = eitherResourceName.left().value(); + + Either<ComponentInstance, ResponseFormat> result = createComponentInstanceOnGraph(containerComponent, origComponent, resourceInstance, userId, containerOperation, true); + if (result.isRight()) { + log.debug("Failed to create resource instance {}", containerComponentId); + resultOp = Either.right(result.right().value()); + return resultOp; + + } + + log.debug("Entity on graph is created."); + ComponentInstance resResourceInfo = result.left().value(); + if (associationInfo.getFromNode() == null || associationInfo.getFromNode().isEmpty()) { + associationInfo.setFromNode(resResourceInfo.getUniqueId()); + } else { + associationInfo.setToNode(resResourceInfo.getUniqueId()); + } + + RequirementCapabilityRelDef requirementCapabilityRelDef = associationInfo;// createRequirementCapabilityrelDef(associationInfo); + + Either<RequirementCapabilityRelDef, StorageOperationStatus> resultReqCapDef = componentInstanceOperation.associateResourceInstances(containerComponentId, containerNodeType, requirementCapabilityRelDef, true); + if (resultReqCapDef.isLeft()) { + log.debug("Enty on graph is created."); + RequirementCapabilityRelDef resReqCapabilityRelDef = resultReqCapDef.left().value(); + CreateAndAssotiateInfo resInfo = new CreateAndAssotiateInfo(resResourceInfo, resReqCapabilityRelDef); + resultOp = Either.left(resInfo); + return resultOp; + + } else { + log.info("Failed to associate node {} with node {}", associationInfo.getFromNode(), associationInfo.getToNode()); + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstance(componentsUtils.convertFromStorageResponseForResourceInstance(resultReqCapDef.right().value(), true), "", null)); + return resultOp; + } + + } finally { + unlockComponent(resultOp, containerComponent); + } + } + + private Either<Component, ResponseFormat> getOriginComponentNameFromComponentInstance(ComponentInstance componentInstance, boolean inTransaction) { + Either<Component, ResponseFormat> eitherResponse; + Either<Component, StorageOperationStatus> eitherComponent = getCompInstOriginComponentOperation().getComponent(componentInstance.getComponentUid(), inTransaction); + if (eitherComponent.isRight()) { + log.debug("Failed to get origin component with id {} for component instance {} ", componentInstance.getComponentUid(), componentInstance.getName()); + eitherResponse = Either.right(componentsUtils.getResponseFormatForResourceInstance(componentsUtils.convertFromStorageResponse(eitherComponent.right().value(), ComponentTypeEnum.RESOURCE), "", null)); + } else { + eitherResponse = Either.left(eitherComponent.left().value()); + } + return eitherResponse; + } + + private Either<String, ResponseFormat> handleNameLogic(Component origComponent, ComponentInstance componentInstance, ComponentTypeEnum containerComponentType, String containerComponentId, boolean isCreate, boolean inTransaction) { + Either<String, ResponseFormat> eitherResult; + final ComponentOperation containerOperation = getComponentOperation(containerComponentType); + + Either<Integer, StorageOperationStatus> componentInNumberStatus = containerOperation.increaseAndGetComponentInstanceCounter(containerComponentId, true); + + if (componentInNumberStatus.isRight()) { + log.debug("Failed to get component instance number for container component {} ", containerComponentId); + eitherResult = Either.right(componentsUtils.getResponseFormatForResourceInstance(componentsUtils.convertFromStorageResponseForResourceInstance(componentInNumberStatus.right().value(), true), "", null)); + } else { + String resourceInNumber = componentInNumberStatus.left().value().toString(); + eitherResult = Either.left(resourceInNumber); + } + + if (eitherResult.isLeft()) { + Either<Boolean, ResponseFormat> eitherSpecificLogic; + if (isCreate) { + eitherSpecificLogic = handleNameLogicForNewComponentInstance(origComponent, componentInstance, eitherResult.left().value(), containerComponentType, inTransaction); + } else { + eitherSpecificLogic = handleNameLogicForUpdatingComponentInstance(origComponent, componentInstance, componentInNumberStatus, containerComponentType, inTransaction); + } + if (eitherSpecificLogic.isRight()) { + eitherResult = Either.right(eitherSpecificLogic.right().value()); + } + } + return eitherResult; + } + + private Either<Boolean, ResponseFormat> handleNameLogicForUpdatingComponentInstance(Component origComponent, ComponentInstance componentInstance, Either<Integer, StorageOperationStatus> componentInNumberStatus, + ComponentTypeEnum containerComponentType, boolean inTransaction) { + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + if (componentInstance.getName() == null || componentInstance.getName().isEmpty()) { + if (origComponent == null) { + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(componentInstance, inTransaction); + + if (eitherResourceName.isRight()) { + eitherResult = Either.right(eitherResourceName.right().value()); + return eitherResult; + } + origComponent = eitherResourceName.left().value(); + + String resourceName = origComponent.getName(); + String logicalName = componentInstanceOperation.createComponentInstLogicalName(componentInNumberStatus.left().value().toString(), resourceName); + componentInstance.setName(logicalName); + if (containerComponentType == ComponentTypeEnum.RESOURCE) { + Resource resource = (Resource) origComponent; + componentInstance.setToscaComponentName(resource.getToscaResourceName()); + } + + } + } + + Either<Boolean, ResponseFormat> eitherValidation = validateComponentInstanceName(componentInstance.getName(), componentInstance, false); + if (eitherValidation.isRight()) { + eitherResult = Either.right(eitherValidation.right().value()); + } + return eitherResult; + } + + private Either<Boolean, ResponseFormat> handleNameLogicForNewComponentInstance(Component origComponent, ComponentInstance componentInstance, String resourceInNumber, ComponentTypeEnum containerComponentType, boolean inTransaction) { + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + + if (origComponent == null) { + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(componentInstance, inTransaction); + + if (eitherResourceName.isRight()) { + eitherResult = Either.right(eitherResourceName.right().value()); + return eitherResult; + } + + origComponent = eitherResourceName.left().value(); + } + + String resourceName = origComponent.getName(); + componentInstance.setComponentName(resourceName); + if (componentInstance.getName() == null || componentInstance.getName().isEmpty()) + componentInstance.setName(resourceName); + String logicalName = componentInstanceOperation.createComponentInstLogicalName(resourceInNumber, componentInstance.getName()); + + Either<Boolean, ResponseFormat> eitherValidation = validateComponentInstanceName(logicalName, componentInstance, true); + if (eitherValidation.isRight()) { + eitherResult = Either.right(eitherValidation.right().value()); + } + if (containerComponentType == ComponentTypeEnum.RESOURCE) { + Resource resource = (Resource) origComponent; + componentInstance.setToscaComponentName(resource.getToscaResourceName()); + } + + return eitherResult; + } + + public Either<ComponentInstance, ResponseFormat> createComponentInstanceOnGraph(String containerComponentParam, org.openecomp.sdc.be.model.Component containerComponent, Component origComponent, ComponentInstance componentInstance, String userId, + boolean needLock, boolean inTransaction) { + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + final ComponentOperation containerOperation = getComponentOperation(containerComponentType); + Either<ComponentInstance, ResponseFormat> resultOp = null; + if (needLock) { + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "createComponentInstance"); + + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + try { + resultOp = createComponentInstanceOnGraph(containerComponent, origComponent, componentInstance, userId, containerOperation, inTransaction); + return resultOp; + + } finally { + if (needLock) + unlockComponent(resultOp, containerComponent); + } + + } + + private Map<String, String> getExistingEnvVersions(ComponentInstance componentInstance) { + if (null == componentInstance.getDeploymentArtifacts()) + return null; + return componentInstance.getDeploymentArtifacts().values() + //filter env artifacts + .stream().filter(p -> p.getArtifactType().equals(ArtifactTypeEnum.HEAT_ENV.getType())) + //map name to version + .collect(Collectors.toMap(a -> a.getArtifactName(), a -> a.getArtifactVersion())); + } + + private Either<ComponentInstance, ResponseFormat> createComponentInstanceOnGraph(org.openecomp.sdc.be.model.Component containerComponent, Component origComponent, ComponentInstance componentInstance, String userId, + ComponentOperation containerOperation, boolean inTransaction) { + Either<ComponentInstance, ResponseFormat> resultOp; + boolean nameAlreadyExist = true; + String resourceInNumber = ""; + String containerComponentId = containerComponent.getUniqueId(); + ComponentTypeEnum containerComponentType = containerComponent.getComponentType(); + NodeTypeEnum containerNodeType = containerComponentType.getNodeType(); + NodeTypeEnum compInstNodeType = getNodeTypeOfComponentInstanceOrigin(); + while (nameAlreadyExist) { + + Either<String, ResponseFormat> eitherNameLogic = handleNameLogic(origComponent, componentInstance, containerComponent.getComponentType(), containerComponent.getUniqueId(), true, inTransaction); + if (eitherNameLogic.isRight()) { + return Either.right(eitherNameLogic.right().value()); + } else { + resourceInNumber = eitherNameLogic.left().value(); + } + + Either<Boolean, StorageOperationStatus> isNameExistStatus = componentInstanceOperation.isComponentInstanceNameExist(containerComponentId, containerNodeType, null, componentInstance.getNormalizedName()); + if (isNameExistStatus.isRight()) { + log.debug("Failed to check if component instance name exists for container component {}", containerComponentId); + + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND, componentInstance.getName(), containerComponentId)); + return resultOp; + } + nameAlreadyExist = isNameExistStatus.left().value(); + + } + + Either<ComponentInstance, StorageOperationStatus> result = componentInstanceOperation.createComponentInstance(containerComponentId, containerNodeType, resourceInNumber, componentInstance, compInstNodeType, inTransaction); + + if (result.isRight()) { + log.debug("Failed to create entry on graph for component instance {}", componentInstance.getName()); + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstance(componentsUtils.convertFromStorageResponseForResourceInstance(result.right().value(), true), "", null)); + return resultOp; + } + + log.debug("Entity on graph is created."); + ComponentInstance compInst = result.left().value(); + + Map<String, String> existingEnvVersions = getExistingEnvVersions(componentInstance); + Either<ActionStatus, ResponseFormat> addComponentInstanceArtifacts = addComponentInstanceArtifacts(containerComponent, compInst, userId, inTransaction, existingEnvVersions); + if (addComponentInstanceArtifacts.isRight()) { + log.debug("Failed to create component instance {}", componentInstance.getName()); + resultOp = Either.right(addComponentInstanceArtifacts.right().value()); + return resultOp; + } + + resultOp = Either.left(compInst); + return resultOp; + } + + /** + * addResourceInstanceArtifacts - add artifacts (HEAT_ENV) to resource instance The instance artifacts are generated from the resource's artifacts + * + * @param componentInstance + * @param userId + * @param existingEnvVersions + * @param containerComponentId + * + * @return + */ + protected Either<ActionStatus, ResponseFormat> addComponentInstanceArtifacts(org.openecomp.sdc.be.model.Component containerComponent, ComponentInstance componentInstance, String userId, boolean inTransaction, + Map<String, String> existingEnvVersions) { + log.debug("add artifacts to resource instance"); + + ActionStatus status = setResourceArtifactsOnResourceInstance(componentInstance); + if (!ActionStatus.OK.equals(status)) { + ResponseFormat resultOp = componentsUtils.getResponseFormatForResourceInstance(status, "", null); + return Either.right(resultOp); + } + + // generate heat_env if necessary + Map<String, ArtifactDefinition> componentDeploymentArtifacts = componentInstance.getDeploymentArtifacts(); + if (componentDeploymentArtifacts == null) { + return Either.left(ActionStatus.OK); + } + Map<String, ArtifactDefinition> finalDeploymentArtifacts = new HashMap<String, ArtifactDefinition>(componentDeploymentArtifacts); + for (ArtifactDefinition artifact : componentDeploymentArtifacts.values()) { + // if (artifact.getArtifactType().equalsIgnoreCase( + // ArtifactTypeEnum.HEAT.getType())) { + String type = artifact.getArtifactType(); + + if (!(type.equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType()) || type.equalsIgnoreCase(ArtifactTypeEnum.HEAT_NET.getType()) || type.equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType()))) { + continue; + } + + if (artifact.checkEsIdExist()) { + Map<String, Object> deploymentResourceArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getDeploymentResourceInstanceArtifacts(); + if (deploymentResourceArtifacts == null) { + log.debug("no deployment artifacts are configured for resource instance"); + break; + } + Map<String, Object> placeHolderData = (Map<String, Object>) deploymentResourceArtifacts.get(HEAT_ENV_NAME); + + String envLabel = (artifact.getArtifactLabel() + HEAT_ENV_SUFFIX).toLowerCase(); + Either<ArtifactDefinition, ResponseFormat> createArtifactPlaceHolder = artifactBusinessLogic.createArtifactPlaceHolderInfo(componentInstance.getUniqueId(), envLabel, placeHolderData, userId, ArtifactGroupTypeEnum.DEPLOYMENT, + inTransaction); + if (createArtifactPlaceHolder.isRight()) { + return Either.right(createArtifactPlaceHolder.right().value()); + } + ArtifactDefinition artifactHeatEnv = createArtifactPlaceHolder.left().value(); + + artifactHeatEnv.setHeatParamsUpdateDate(System.currentTimeMillis()); + artifactHeatEnv.setTimeout(0); + buildHeatEnvFileName(artifact, artifactHeatEnv, placeHolderData); + + // rbetzer - keep env artifactVersion - changeComponentInstanceVersion flow + handleEnvArtifactVersion(artifactHeatEnv, existingEnvVersions); + Either<ArtifactDefinition, StorageOperationStatus> addHeatEnvArtifact = artifactBusinessLogic.addHeatEnvArtifact(artifactHeatEnv, artifact, componentInstance.getUniqueId(), NodeTypeEnum.ResourceInstance, true); + if (addHeatEnvArtifact.isRight()) { + log.debug("failed to create heat env artifact on resource instance"); + return Either.right(componentsUtils.getResponseFormatForResourceInstance(componentsUtils.convertFromStorageResponseForResourceInstance(addHeatEnvArtifact.right().value(), false), "", null)); + } + + ArtifactDefinition artifactDefinition = addHeatEnvArtifact.left().value(); + if (artifact.getHeatParameters() != null) { + List<HeatParameterDefinition> heatEnvParameters = new ArrayList<HeatParameterDefinition>(); + for (HeatParameterDefinition parameter : artifact.getHeatParameters()) { + HeatParameterDefinition heatEnvParameter = new HeatParameterDefinition(parameter); + heatEnvParameter.setDefaultValue(parameter.getCurrentValue()); + heatEnvParameters.add(heatEnvParameter); + } + artifactDefinition.setHeatParameters(heatEnvParameters); + } + finalDeploymentArtifacts.put(envLabel, artifactDefinition); + + // audit + EnumMap<AuditingFieldsKeysEnum, Object> artifactAuditingFields = artifactBusinessLogic.createArtifactAuditingFields(artifactDefinition, "", artifactDefinition.getUniqueId()); + artifactAuditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, componentInstance.getName()); + handleAuditing(AuditingActionEnum.ARTIFACT_UPLOAD, containerComponent, userId, artifactAuditingFields, inTransaction); + } + // } + } + componentInstance.setDeploymentArtifacts(finalDeploymentArtifacts); + return Either.left(ActionStatus.OK); + } + + private void handleAuditing(AuditingActionEnum artifactUpload, org.openecomp.sdc.be.model.Component containerComponent, String userId, EnumMap<AuditingFieldsKeysEnum, Object> artifactAuditingFields, boolean inTransaction) { + + Either<User, ActionStatus> user = userAdmin.getUser(userId, inTransaction); + if (user.isRight()) { + log.debug("failed to get user properties from graph for audit"); + return; + } + + componentsUtils.auditComponent(componentsUtils.getResponseFormat(ActionStatus.OK), user.left().value(), containerComponent, "", "", AuditingActionEnum.ARTIFACT_UPLOAD, ComponentTypeEnum.RESOURCE_INSTANCE, artifactAuditingFields); + + } + + private void handleEnvArtifactVersion(ArtifactDefinition heatEnvArtifact, Map<String, String> existingEnvVersions) { + if (null != existingEnvVersions) { + String prevVersion = existingEnvVersions.get(heatEnvArtifact.getArtifactName()); + if (null != prevVersion) { + heatEnvArtifact.setArtifactVersion(prevVersion); + } + } + } + + private void buildHeatEnvFileName(ArtifactDefinition heatArtifact, ArtifactDefinition heatEnvArtifact, Map<String, Object> placeHolderData) { + String heatExtension = GeneralUtility.getFilenameExtension(heatArtifact.getArtifactName()); + String envExtension = (String) placeHolderData.get(ARTIFACT_PLACEHOLDER_FILE_EXTENSION); + String fileName = heatArtifact.getArtifactName().replaceAll("." + heatExtension, "." + envExtension); + heatEnvArtifact.setArtifactName(fileName); + } + + private ActionStatus setResourceArtifactsOnResourceInstance(ComponentInstance resourceInstance) { + Either<Map<String, ArtifactDefinition>, StorageOperationStatus> getResourceDeploymentArtifacts = artifactBusinessLogic.getArtifacts(resourceInstance.getComponentUid(), NodeTypeEnum.Resource, true, ArtifactGroupTypeEnum.DEPLOYMENT); + + Map<String, ArtifactDefinition> deploymentArtifacts = new HashMap<String, ArtifactDefinition>(); + if (getResourceDeploymentArtifacts.isRight()) { + StorageOperationStatus status = getResourceDeploymentArtifacts.right().value(); + if (!status.equals(StorageOperationStatus.NOT_FOUND)) { + log.debug("Failed to fetch resource artifacts. status is {}", status); + return componentsUtils.convertFromStorageResponseForResourceInstance(status, true); + } + } else { + deploymentArtifacts = getResourceDeploymentArtifacts.left().value(); + } + + if (!deploymentArtifacts.isEmpty()) { + Map<String, ArtifactDefinition> tempDeploymentArtifacts = new HashMap<String, ArtifactDefinition>(deploymentArtifacts); + for (Entry<String, ArtifactDefinition> artifact : deploymentArtifacts.entrySet()) { + if (!artifact.getValue().checkEsIdExist()) { + tempDeploymentArtifacts.remove(artifact.getKey()); + } + } + + resourceInstance.setDeploymentArtifacts(tempDeploymentArtifacts); + } + + return ActionStatus.OK; + } + + public Either<ComponentInstance, ResponseFormat> updateComponentInstance(String containerComponentParam, String containerComponentId, String componentInstanceId, String userId, ComponentInstance componentInstance) { + return updateComponentInstance(containerComponentParam, containerComponentId, componentInstanceId, userId, componentInstance, false, true, true); + } + + public Either<ComponentInstance, ResponseFormat> updateComponentInstance(String containerComponentParam, String containerComponentId, String componentInstanceId, String userId, ComponentInstance componentInstance, boolean inTransaction, + boolean needLock, boolean createNewTransaction) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "update Component Instance", inTransaction); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<ComponentInstance, ResponseFormat> resultOp = null; + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(containerComponentId, containerComponentType, inTransaction, createNewTransaction); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + ComponentTypeEnum instanceType = getComponentType(containerComponentType); + Either<Boolean, StorageOperationStatus> validateParentStatus = componentInstanceOperation.validateParent(containerComponentId, componentInstanceId, inTransaction); + if (validateParentStatus.isRight()) { + log.debug("Failed to get component instance {} on service {}", componentInstanceId, containerComponentId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, componentInstance.getName(), instanceType.getValue().toLowerCase())); + return resultOp; + } + Boolean isPrentValid = validateParentStatus.left().value(); + if (!isPrentValid) { + resultOp = Either.right( + componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, componentInstance.getName(), instanceType.getValue().toLowerCase(), containerComponentType.getValue().toLowerCase(), containerComponentId)); + return resultOp; + + } + + if (needLock) { + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "updateComponentInstance"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + try { + + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(componentInstance, inTransaction); + + if (eitherResourceName.isRight()) { + resultOp = Either.right(eitherResourceName.right().value()); + return resultOp; + } + Component origComponent = eitherResourceName.left().value(); + + resultOp = updateComponentInstance(containerComponentId, containerComponentType, origComponent, componentInstanceId, componentInstance, inTransaction); + return resultOp; + + } finally { + if (needLock) + unlockComponent(resultOp, containerComponent); + } + } + + // New Multiple Instance Update API + public Either<List<ComponentInstance>, ResponseFormat> updateComponentInstance(String containerComponentParam, String containerComponentId, String userId, List<ComponentInstance> componentInstanceList, boolean needLock, + boolean createNewTransaction) { + + Either<List<ComponentInstance>, ResponseFormat> resultOp = null; + org.openecomp.sdc.be.model.Component containerComponent = null; + try { + Either<User, ResponseFormat> resp = validateUserExists(userId, "update Component Instance", true); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + + ComponentParametersView componentFilter = new ComponentParametersView(); + componentFilter.disableAll(); + componentFilter.setIgnoreUsers(false); + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExistsByFilter(containerComponentId, containerComponentType, componentFilter, true); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + + containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + + ComponentTypeEnum instanceType = getComponentType(containerComponentType); + + for (ComponentInstance componentInstance : componentInstanceList) { + Either<Boolean, StorageOperationStatus> validateParentStatus = componentInstanceOperation.validateParent(containerComponentId, componentInstance.getUniqueId(), true); + if (validateParentStatus.isRight()) { + log.debug("Failed to get component instance {} on service {}", componentInstance.getUniqueId(), containerComponentId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, componentInstance.getName(), instanceType.getValue().toLowerCase())); + return resultOp; + } + Boolean isPrentValid = validateParentStatus.left().value(); + if (!isPrentValid) { + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, componentInstance.getName(), instanceType.getValue().toLowerCase(), containerComponentType.getValue().toLowerCase(), + containerComponentId)); + return resultOp; + } + } + + if (needLock) { + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "updateComponentInstance"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + List<ComponentInstance> updatedList = new ArrayList<>(); + for (ComponentInstance componentInstance : componentInstanceList) { + + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(componentInstance, true); + + if (eitherResourceName.isRight()) { + resultOp = Either.right(eitherResourceName.right().value()); + return resultOp; + } + Component origComponent = eitherResourceName.left().value(); + + Either<ComponentInstance, ResponseFormat> resultSingleUpdate = updateComponentInstance(containerComponentId, containerComponentType, origComponent, componentInstance.getUniqueId(), componentInstance, true); + + if (resultSingleUpdate.isRight()) { + resultOp = Either.right(resultSingleUpdate.right().value()); + return resultOp; + } + updatedList.add(resultSingleUpdate.left().value()); + } + + resultOp = Either.left(updatedList); + return resultOp; + + } finally { + if (needLock) { + unlockComponent(resultOp, containerComponent); + } + } + } + + private ComponentTypeEnum getComponentType(ComponentTypeEnum containerComponentType) { + if (ComponentTypeEnum.PRODUCT.equals(containerComponentType)) { + return ComponentTypeEnum.SERVICE_INSTANCE; + } else { + return ComponentTypeEnum.RESOURCE_INSTANCE; + } + } + + public Either<ComponentInstance, ResponseFormat> updateComponentInstance(String containerComponentParam, org.openecomp.sdc.be.model.Component containerComponent, org.openecomp.sdc.be.model.Component origComponent, String componentInstanceId, + ComponentInstance componentInstance, boolean needLock, boolean inTransaction) { + Either<ComponentInstance, ResponseFormat> resultOp = null; + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + if (needLock) { + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "updateComponentInstance"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + try { + + resultOp = updateComponentInstance(containerComponent.getUniqueId(), containerComponentType, origComponent, componentInstanceId, componentInstance, inTransaction); + return resultOp; + + } finally { + if (needLock) + unlockComponent(resultOp, containerComponent); + } + + } + + private Either<ComponentInstance, ResponseFormat> updateComponentInstance(String containerComponentId, ComponentTypeEnum containerComponentType, org.openecomp.sdc.be.model.Component origComponent, String componentInstanceId, + ComponentInstance componentInstance, boolean inTransaction) { + Either<ComponentInstance, ResponseFormat> resultOp; + + Either<String, ResponseFormat> eitherNameLogic = handleNameLogic(origComponent, componentInstance, containerComponentType, containerComponentId, false, inTransaction); + if (eitherNameLogic.isRight()) { + return Either.right(eitherNameLogic.right().value()); + } + NodeTypeEnum containerNodeType = containerComponentType.getNodeType(); + + Either<Boolean, StorageOperationStatus> isNameExistStatus = componentInstanceOperation.isComponentInstanceNameExist(containerComponentId, containerNodeType, componentInstanceId, componentInstance.getNormalizedName()); + if (isNameExistStatus.isRight()) { + log.debug("Failed to get resource instance names for service {}", containerComponentId); + + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND, componentInstance.getName(), containerComponentId)); + return resultOp; + } + Boolean isNameExist = isNameExistStatus.left().value(); + if (isNameExist) { + containerComponentType = getComponentTypeOfComponentInstance(); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, containerComponentType.getValue(), componentInstance.getName())); + return resultOp; + + } + + log.debug("Try to update entry on graph"); + Either<ComponentInstance, StorageOperationStatus> result = componentInstanceOperation.updateResourceInstance(containerComponentId, containerNodeType, componentInstanceId, componentInstance, inTransaction); + + if (result.isLeft()) { + log.debug("Enty on graph is updated."); + ComponentInstance resResourceInfo = result.left().value(); + resultOp = Either.left(resResourceInfo); + return resultOp; + + } else { + log.debug("Failed to update entry on graph for resource instance {}", componentInstance.getName()); + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstance(componentsUtils.convertFromStorageResponseForResourceInstance(result.right().value(), false), "", componentInstance.getName())); + return resultOp; + } + + } + + public Either<ComponentInstance, ResponseFormat> deleteComponentInstance(String containerComponentParam, String containerComponentId, String resourceInstanceId, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Component Instance", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(containerComponentId, containerComponentType, false, true); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "deleteComponentInstance"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + // validate resource + /* + * if (!ComponentValidationUtils.canWorkOnComponent(containerComponentId, serviceOperation, userId)) { log.info( "Restricted operation for user {} on service {}", userId, containerComponentId); return Either.right(componentsUtils + * .getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); } // lock resource StorageOperationStatus lockStatus = graphLockOperation.lockComponent( containerComponentId, NodeTypeEnum.Service); if (lockStatus != StorageOperationStatus.OK) { + * log.debug("Failed to lock service {}", containerComponentId); resultOp = Either.right(componentsUtils .getResponseFormat(componentsUtils .convertFromStorageResponse(lockStatus))); return resultOp; } + */ + Either<ComponentInstance, ResponseFormat> resultOp = null; + try { + resultOp = deleteComponentInstance(containerComponentId, resourceInstanceId, containerComponentType); + return resultOp; + + } finally { + /* + * if (resultOp == null || resultOp.isRight()) { titanGenericDao.rollback(); } else { titanGenericDao.commit(); } graphLockOperation.unlockComponent(containerComponentId, NodeTypeEnum.Service); + */ + unlockComponent(resultOp, containerComponent); + } + } + + private Either<ComponentInstance, ResponseFormat> deleteComponentInstance(String containerComponentId, String resourceInstanceId, ComponentTypeEnum containerComponentType) { + Either<ComponentInstance, ResponseFormat> resultOp; + NodeTypeEnum containerNodeType = containerComponentType.getNodeType(); + Either<ComponentInstance, StorageOperationStatus> result = componentInstanceOperation.deleteComponentInstance(containerNodeType, containerComponentId, resourceInstanceId, true); + + if (result.isRight()) { + log.debug("Failed to delete entry on graph for resourceInstance {}", resourceInstanceId); + ActionStatus status = componentsUtils.convertFromStorageResponse(result.right().value(), containerComponentType); + // TODO check + /* + * if (ActionStatus.SERVICE_NOT_FOUND.equals(status)) { resultOp = Either .right(componentsUtils .getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND)); } else { + */ + resultOp = Either.right(componentsUtils.getResponseFormat(status, resourceInstanceId)); + // } + return resultOp; + } + ComponentInstance resResourceInfo = result.left().value(); + resultOp = Either.left(resResourceInfo); + + log.debug("Entry on graph is deleted. Exist more connections on this artifact."); + + Map<String, ArtifactDefinition> deploymentArtifacts = resResourceInfo.getDeploymentArtifacts(); + if (deploymentArtifacts != null && !deploymentArtifacts.isEmpty()) { + StorageOperationStatus deleteArtifactsIfNotOnGraph = artifactBusinessLogic.deleteAllComponentArtifactsIfNotOnGraph(new ArrayList<ArtifactDefinition>(deploymentArtifacts.values())); + if (!deleteArtifactsIfNotOnGraph.equals(StorageOperationStatus.OK)) { + log.debug("failed to delete artifact payload. status={}", deleteArtifactsIfNotOnGraph.name()); + resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), resourceInstanceId)); + } + + } + return resultOp; + } + + public Either<RequirementCapabilityRelDef, ResponseFormat> associateRIToRI(String componentId, String userId, RequirementCapabilityRelDef requirementDef, ComponentTypeEnum componentTypeEnum) { + return associateRIToRI(componentId, userId, requirementDef, componentTypeEnum, false, true, true); + } + + public Either<RequirementCapabilityRelDef, ResponseFormat> associateRIToRI(String componentId, String userId, RequirementCapabilityRelDef requirementDef, ComponentTypeEnum componentTypeEnum, boolean inTransaction, boolean needLock, + boolean createNewTransaction) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "associate Ri To RI", inTransaction); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<RequirementCapabilityRelDef, ResponseFormat> resultOp = null; + + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(componentId, componentTypeEnum, inTransaction, createNewTransaction); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + if (needLock) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "associateRIToRI"); + + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + try { + + resultOp = associateRIToRIOnGraph(componentId, requirementDef, componentTypeEnum, inTransaction); + + return resultOp; + + } finally { + if (needLock) + unlockComponent(resultOp, containerComponent); + } + } + + public Either<RequirementCapabilityRelDef, ResponseFormat> associateRIToRIOnGraph(String componentId, RequirementCapabilityRelDef requirementDef, ComponentTypeEnum componentTypeEnum, boolean inTransaction) { + + log.debug("Try to create entry on graph"); + Either<RequirementCapabilityRelDef, ResponseFormat> resultOp = null; + + Either<RequirementCapabilityRelDef, StorageOperationStatus> result = componentInstanceOperation.associateResourceInstances(componentId, componentTypeEnum.getNodeType(), requirementDef, inTransaction); + + if (result.isLeft()) { + log.debug("Enty on graph is created."); + RequirementCapabilityRelDef requirementCapabilityRelDef = result.left().value(); + resultOp = Either.left(requirementCapabilityRelDef); + return resultOp; + + } else { + log.debug("Failed to associate node {} with node {}", requirementDef.getFromNode(), requirementDef.getToNode()); + String fromNameOrId = ""; + String toNameOrId = ""; + Either<ComponentInstance, StorageOperationStatus> fromResult = componentInstanceOperation.getResourceInstanceById(requirementDef.getFromNode()); + Either<ComponentInstance, StorageOperationStatus> toResult = componentInstanceOperation.getResourceInstanceById(requirementDef.getToNode()); + + toNameOrId = requirementDef.getFromNode(); + fromNameOrId = requirementDef.getFromNode(); + if (fromResult.isLeft()) { + fromNameOrId = fromResult.left().value().getName(); + } + if (toResult.isLeft()) { + toNameOrId = toResult.left().value().getName(); + } + + resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponseForResourceInstance(result.right().value(), true), fromNameOrId, toNameOrId, requirementDef.getRelationships().get(0).getRequirement())); + + return resultOp; + } + + } + + public Either<RequirementCapabilityRelDef, ResponseFormat> dissociateRIFromRI(String componentId, String userId, RequirementCapabilityRelDef requirementDef, ComponentTypeEnum componentTypeEnum) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "dissociate RI From RI", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<RequirementCapabilityRelDef, ResponseFormat> resultOp = null; + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(componentId, componentTypeEnum, false, true); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "associateRIToRI"); + + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + try { + log.debug("Try to create entry on graph"); + Either<RequirementCapabilityRelDef, StorageOperationStatus> result = componentInstanceOperation.dissociateResourceInstances(componentId, componentTypeEnum.getNodeType(), requirementDef, true); + if (result.isLeft()) { + log.debug("Enty on graph is created."); + RequirementCapabilityRelDef requirementCapabilityRelDef = result.left().value(); + resultOp = Either.left(requirementCapabilityRelDef); + return resultOp; + + } else { + + log.debug("Failed to dissocaite node {} from node {}", requirementDef.getFromNode(), requirementDef.getToNode()); + String fromNameOrId = ""; + String toNameOrId = ""; + Either<ComponentInstance, StorageOperationStatus> fromResult = componentInstanceOperation.getResourceInstanceById(requirementDef.getFromNode()); + Either<ComponentInstance, StorageOperationStatus> toResult = componentInstanceOperation.getResourceInstanceById(requirementDef.getToNode()); + + toNameOrId = requirementDef.getFromNode(); + fromNameOrId = requirementDef.getFromNode(); + if (fromResult.isLeft()) { + fromNameOrId = fromResult.left().value().getName(); + } + if (toResult.isLeft()) { + toNameOrId = toResult.left().value().getName(); + } + + resultOp = Either + .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponseForResourceInstance(result.right().value(), true), fromNameOrId, toNameOrId, requirementDef.getRelationships().get(0).getRequirement())); + return resultOp; + } + } finally { + unlockComponent(resultOp, containerComponent); + } + } + + private Either<ComponentInstanceAttribute, ResponseFormat> updateAttributeValue(ComponentInstanceAttribute attribute, String resourceInstanceId) { + Either<ComponentInstanceAttribute, StorageOperationStatus> eitherAttribute = componentInstanceOperation.updateAttributeValueInResourceInstance(attribute, resourceInstanceId, true); + Either<ComponentInstanceAttribute, ResponseFormat> result; + if (eitherAttribute.isLeft()) { + log.debug("Attribute value {} was updated on graph.", attribute.getValueUniqueUid()); + ComponentInstanceAttribute instanceAttribute = eitherAttribute.left().value(); + + result = Either.left(instanceAttribute); + + } else { + log.debug("Failed to update attribute value {} in resource instance {}", attribute, resourceInstanceId); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(eitherAttribute.right().value()); + + result = Either.right(componentsUtils.getResponseFormat(actionStatus, "")); + + } + return result; + } + + private Either<ComponentInstanceInput, ResponseFormat> updateInputValue(ComponentInstanceInput input, String resourceInstanceId) { + Either<ComponentInstanceInput, StorageOperationStatus> eitherInput = componentInstanceOperation.updateInputValueInResourceInstance(input, resourceInstanceId, true); + Either<ComponentInstanceInput, ResponseFormat> result; + if (eitherInput.isLeft()) { + log.debug("Input value {} was updated on graph.", input.getValueUniqueUid()); + ComponentInstanceInput instanceInput = eitherInput.left().value(); + + result = Either.left(instanceInput); + + } else { + log.debug("Failed to update input value {} in resource instance {}", input, resourceInstanceId); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(eitherInput.right().value()); + + result = Either.right(componentsUtils.getResponseFormat(actionStatus, "")); + + } + return result; + } + + private Either<ComponentInstanceAttribute, ResponseFormat> createAttributeValue(ComponentInstanceAttribute attribute, String resourceInstanceId) { + + Either<ComponentInstanceAttribute, ResponseFormat> result; + + Wrapper<Integer> indexCounterWrapper = new Wrapper<>(); + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + validateIncrementCounter(resourceInstanceId, GraphPropertiesDictionary.ATTRIBUTE_COUNTER, indexCounterWrapper, errorWrapper); + + if (!errorWrapper.isEmpty()) { + result = Either.right(errorWrapper.getInnerElement()); + } else { + Either<ComponentInstanceAttribute, StorageOperationStatus> eitherAttribute = componentInstanceOperation.addAttributeValueToResourceInstance(attribute, resourceInstanceId, indexCounterWrapper.getInnerElement(), true); + if (eitherAttribute.isLeft()) { + log.debug("Attribute value was added to resource instance {}", resourceInstanceId); + ComponentInstanceAttribute instanceAttribute = eitherAttribute.left().value(); + result = Either.left(instanceAttribute); + + } else { + log.debug("Failed to add attribute value {} to resource instance {}", attribute, resourceInstanceId); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(eitherAttribute.right().value()); + result = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); + + } + } + return result; + } + + /** + * Create Or Updates Attribute Instance + * + * @param componentTypeEnum + * @param componentId + * @param resourceInstanceId + * @param attribute + * @param userId + * @return + */ + public Either<ComponentInstanceAttribute, ResponseFormat> createOrUpdateAttributeValue(ComponentTypeEnum componentTypeEnum, String componentId, String resourceInstanceId, ComponentInstanceAttribute attribute, String userId) { + Either<ComponentInstanceAttribute, ResponseFormat> result = null; + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + + validateUserExist(userId, "create Or Update Attribute Value", errorWrapper); + if (errorWrapper.isEmpty()) { + validateComponentTypeEnum(componentTypeEnum, "CreateOrUpdateAttributeValue", errorWrapper); + } + if (errorWrapper.isEmpty()) { + validateCanWorkOnComponent(componentId, componentTypeEnum, userId, errorWrapper); + } + if (errorWrapper.isEmpty()) { + validateComponentLock(componentId, componentTypeEnum, errorWrapper); + } + + try { + if (errorWrapper.isEmpty()) { + final boolean isCreate = Objects.isNull(attribute.getValueUniqueUid()); + if (isCreate) { + result = createAttributeValue(attribute, resourceInstanceId); + } else { + result = updateAttributeValue(attribute, resourceInstanceId); + } + } else { + result = Either.right(errorWrapper.getInnerElement()); + } + return result; + } + + finally { + if (result == null || result.isRight()) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + // unlock resource + graphLockOperation.unlockComponent(componentId, componentTypeEnum.getNodeType()); + } + } + + public Either<ComponentInstanceProperty, ResponseFormat> createOrUpdatePropertyValue(ComponentTypeEnum componentTypeEnum, String componentId, String resourceInstanceId, ComponentInstanceProperty property, String userId) { + + Either<ComponentInstanceProperty, ResponseFormat> resultOp = null; + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Or Update Property Value", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + if (componentTypeEnum == null) { + BeEcompErrorManager.getInstance().logInvalidInputError("CreateOrUpdatePropertyValue", "invalid component type", ErrorSeverity.INFO); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED)); + return resultOp; + } + + IComponentOperation componentOperation = getIComponentOperation(componentTypeEnum); + + if (!ComponentValidationUtils.canWorkOnComponent(componentId, componentOperation, userId)) { + log.info("Restricted operation for user {} on service {}", userId, componentId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return resultOp; + } + // lock resource + StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType()); + if (lockStatus != StorageOperationStatus.OK) { + log.debug("Failed to lock service {}", componentId); + resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus))); + return resultOp; + } + try { + String propertyValueUid = property.getValueUniqueUid(); + if (propertyValueUid == null) { + + Either<Integer, StorageOperationStatus> counterRes = componentInstanceOperation.increaseAndGetResourceInstanceSpecificCounter(resourceInstanceId, GraphPropertiesDictionary.PROPERTY_COUNTER, true); + + if (counterRes.isRight()) { + log.debug("increaseAndGetResourcePropertyCounter failed resource instance {} property {}", resourceInstanceId, property); + StorageOperationStatus status = counterRes.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status); + resultOp = Either.right(componentsUtils.getResponseFormat(actionStatus)); + } + Integer index = counterRes.left().value(); + Either<ComponentInstanceProperty, StorageOperationStatus> result = componentInstanceOperation.addPropertyValueToResourceInstance(property, resourceInstanceId, index, true); + + if (result.isLeft()) { + log.debug("Property value was added to resource instance {}", resourceInstanceId); + ComponentInstanceProperty instanceProperty = result.left().value(); + + resultOp = Either.left(instanceProperty); + return resultOp; + + } else { + log.debug("Failed to add property value {} to resource instance {}", property, resourceInstanceId); + // TODO: esofer add error + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(result.right().value()); + + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); + + return resultOp; + } + + } else { + Either<ComponentInstanceProperty, StorageOperationStatus> result = componentInstanceOperation.updatePropertyValueInResourceInstance(property, resourceInstanceId, true); + + if (result.isLeft()) { + log.debug("Property value {} was updated on graph.", property.getValueUniqueUid()); + ComponentInstanceProperty instanceProperty = result.left().value(); + + resultOp = Either.left(instanceProperty); + return resultOp; + + } else { + log.debug("Failed to update property value {} in resource instance {}", property, resourceInstanceId); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(result.right().value()); + + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); + + return resultOp; + } + } + + } finally { + if (resultOp == null || resultOp.isRight()) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + // unlock resource + graphLockOperation.unlockComponent(componentId, componentTypeEnum.getNodeType()); + } + + } + + public Either<ComponentInstanceInput, ResponseFormat> createOrUpdateInputValue(ComponentTypeEnum componentTypeEnum, String componentId, String resourceInstanceId, ComponentInstanceInput inputProperty, String userId) { + + Either<ComponentInstanceInput, ResponseFormat> resultOp = null; + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Or Update Input Value", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + if (componentTypeEnum == null) { + BeEcompErrorManager.getInstance().logInvalidInputError("createOrUpdateInputValue", "invalid component type", ErrorSeverity.INFO); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED)); + return resultOp; + } + + IComponentOperation componentOperation = getIComponentOperation(componentTypeEnum); + + if (!ComponentValidationUtils.canWorkOnComponent(componentId, componentOperation, userId)) { + log.info("Restricted operation for user {} on service {}", userId, componentId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return resultOp; + } + // lock resource + StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType()); + if (lockStatus != StorageOperationStatus.OK) { + log.debug("Failed to lock service {}", componentId); + resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus))); + return resultOp; + } + try { + String propertyValueUid = inputProperty.getValueUniqueUid(); + if (propertyValueUid == null) { + + Either<Integer, StorageOperationStatus> counterRes = componentInstanceOperation.increaseAndGetResourceInstanceSpecificCounter(resourceInstanceId, GraphPropertiesDictionary.INPUT_COUNTER, true); + + if (counterRes.isRight()) { + log.debug("increaseAndGetResourceInputCounter failed resource instance {} inputProperty {}", resourceInstanceId, inputProperty); + StorageOperationStatus status = counterRes.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status); + resultOp = Either.right(componentsUtils.getResponseFormat(actionStatus)); + } + Integer index = counterRes.left().value(); + Either<ComponentInstanceInput, StorageOperationStatus> result = componentInstanceOperation.addInputValueToResourceInstance(inputProperty, resourceInstanceId, index, true); + + if (result.isLeft()) { + log.debug("Property value was added to resource instance {}", resourceInstanceId); + ComponentInstanceInput instanceProperty = result.left().value(); + + resultOp = Either.left(instanceProperty); + return resultOp; + + } else { + log.debug("Failed to add input value {} to resource instance {}", inputProperty, resourceInstanceId); + // TODO: esofer add error + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(result.right().value()); + + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); + + return resultOp; + } + + } else { + Either<ComponentInstanceInput, StorageOperationStatus> result = componentInstanceOperation.updateInputValueInResourceInstance(inputProperty, resourceInstanceId, true); + + if (result.isLeft()) { + log.debug("Input value {} was updated on graph.", inputProperty.getValueUniqueUid()); + ComponentInstanceInput instanceProperty = result.left().value(); + + resultOp = Either.left(instanceProperty); + return resultOp; + + } else { + log.debug("Failed to update property value {} in reosurce instance {}", inputProperty, resourceInstanceId); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(result.right().value()); + + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); + + return resultOp; + } + } + + } finally { + if (resultOp == null || resultOp.isRight()) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + // unlock resource + graphLockOperation.unlockComponent(componentId, componentTypeEnum.getNodeType()); + } + + } + + public Either<ComponentInstanceProperty, ResponseFormat> deletePropertyValue(ComponentTypeEnum componentTypeEnum, String serviceId, String resourceInstanceId, String propertyValueId, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Property Value", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<ComponentInstanceProperty, ResponseFormat> resultOp = null; + + if (componentTypeEnum == null) { + BeEcompErrorManager.getInstance().logInvalidInputError("CreateOrUpdatePropertyValue", "invalid component type", ErrorSeverity.INFO); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED)); + return resultOp; + } + + IComponentOperation componentOperation = getIComponentOperation(componentTypeEnum); + + if (!ComponentValidationUtils.canWorkOnComponent(serviceId, componentOperation, userId)) { + log.info("Restricted operation for user {} on service {}", userId, serviceId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return resultOp; + } + // lock resource + StorageOperationStatus lockStatus = graphLockOperation.lockComponent(serviceId, componentTypeEnum.getNodeType()); + if (lockStatus != StorageOperationStatus.OK) { + log.debug("Failed to lock service {}", serviceId); + resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus))); + return resultOp; + } + try { + Either<ComponentInstanceProperty, StorageOperationStatus> result = propertyOperation.removePropertyValueFromResourceInstance(propertyValueId, resourceInstanceId, true); + + if (result.isLeft()) { + log.debug("Property value {} was removed from graph.", propertyValueId); + ComponentInstanceProperty instanceProperty = result.left().value(); + + resultOp = Either.left(instanceProperty); + return resultOp; + + } else { + log.debug("Failed to remove property value {} in resource instance {}", propertyValueId, resourceInstanceId); + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(result.right().value()); + + resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); + + return resultOp; + } + + } finally { + if (resultOp == null || resultOp.isRight()) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + // unlock resource + graphLockOperation.unlockComponent(serviceId, componentTypeEnum.getNodeType()); + } + + } + + private Either<Boolean, ResponseFormat> validateComponentInstanceName(String resourceInstanceName, ComponentInstance resourceInstance, boolean isCreate) { + ComponentTypeEnum containerComponentType = getComponentTypeOfComponentInstance(); + if (!isCreate) { + if (resourceInstanceName == null) + return Either.left(true); + } + + if (!ValidationUtils.validateStringNotEmpty(resourceInstanceName)) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, containerComponentType.getValue()); + + return Either.right(errorResponse); + } + resourceInstance.setNormalizedName(ValidationUtils.normaliseComponentInstanceName(resourceInstanceName)); + if (!isCreate) { + if (!ValidationUtils.validateResourceInstanceNameLength(resourceInstanceName)) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT, containerComponentType.getValue(), "" + ValidationUtils.COMPONENT_NAME_MAX_LENGTH); + + return Either.right(errorResponse); + } + if (!ValidationUtils.validateResourceInstanceName(resourceInstanceName)) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPONENT_NAME, containerComponentType.getValue()); + + return Either.right(errorResponse); + } + } + + return Either.left(true); + + } + + private Either<Boolean, ResponseFormat> validateComponentInstanceParentState(ComponentTypeEnum containerComponentType, ComponentInstance resourceInstance) { + String componentId = resourceInstance.getComponentUid(); + Either<? extends Component, StorageOperationStatus> eitherResourceResponse = Either.right(StorageOperationStatus.GENERAL_ERROR); + + ComponentTypeEnum componentType = getComponentTypeByParentComponentType(containerComponentType); + ComponentOperation componentOperation = getComponentOperation(componentType); + if (componentOperation != null) + eitherResourceResponse = componentOperation.getComponent(componentId, true); + + Component component = null; + ResponseFormat errorResponse = null; + if (eitherResourceResponse.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(eitherResourceResponse.right().value(), componentType); + errorResponse = componentsUtils.getResponseFormat(actionStatus, Constants.EMPTY_STRING); + return Either.right(errorResponse); + } + component = eitherResourceResponse.left().value(); + LifecycleStateEnum resourceCurrState = component.getLifecycleState(); + if (resourceCurrState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) { + ActionStatus actionStatus = ActionStatus.ILLEGAL_COMPONENT_STATE; + errorResponse = componentsUtils.getResponseFormat(actionStatus, component.getComponentType().toString(), component.getName(), resourceCurrState.toString()); + return Either.right(errorResponse); + } + return Either.left(true); + } + + public Either<ComponentInstance, ResponseFormat> changeComponentInstanceVersion(String containerComponentParam, String containerComponentId, String componentInstanceId, String userId, ComponentInstance newComponentInstance) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "change Component Instance Version", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<ComponentInstance, ResponseFormat> resultOp = null; + + Either<ComponentTypeEnum, ResponseFormat> validateComponentType = validateComponentType(containerComponentParam); + if (validateComponentType.isRight()) { + return Either.right(validateComponentType.right().value()); + } + + final ComponentTypeEnum containerComponentType = validateComponentType.left().value(); + final ComponentOperation containerOperation = getComponentOperation(containerComponentType); + + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponentExists = validateComponentExists(containerComponentId, containerComponentType, false, true); + if (validateComponentExists.isRight()) { + return Either.right(validateComponentExists.right().value()); + } + org.openecomp.sdc.be.model.Component containerComponent = validateComponentExists.left().value(); + + Either<Boolean, ResponseFormat> validateCanWorkOnComponent = validateCanWorkOnComponent(containerComponent, userId); + if (validateCanWorkOnComponent.isRight()) { + return Either.right(validateCanWorkOnComponent.right().value()); + } + + Either<Boolean, StorageOperationStatus> validateParentStatus = componentInstanceOperation.validateParent(containerComponentId, componentInstanceId, false); + if (validateParentStatus.isRight()) { + log.debug("Failed to get resource instance {} on service {}", componentInstanceId, containerComponentId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND, componentInstanceId)); + return resultOp; + } + Boolean isPrentValid = validateParentStatus.left().value(); + if (!isPrentValid) { + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, componentInstanceId, containerComponentId)); + return resultOp; + + } + + Either<ComponentInstance, StorageOperationStatus> resourceInstanceStatus = componentInstanceOperation.getResourceInstanceById(componentInstanceId); + if (resourceInstanceStatus.isRight()) { + log.debug("Failed to get resource instance {} on service {}", componentInstanceId, containerComponentId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND, componentInstanceId)); + return resultOp; + } + ComponentInstance currentResourceInstance = resourceInstanceStatus.left().value(); + + Either<Boolean, ResponseFormat> lockComponent = lockComponent(containerComponent, "changeComponentInstanceVersion"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + + try { + if (currentResourceInstance.getComponentUid().equals(newComponentInstance.getComponentUid())) { + resultOp = Either.left(currentResourceInstance); + return resultOp; + + } + String resourceId = newComponentInstance.getComponentUid(); + if (!getCompInstOriginComponentOperation().isComponentExist(resourceId)) { + log.debug("resource {} not found.", resourceId); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return resultOp; + } + + // esofer - before deleting component instance, we should keep the + // groups which holds this instance + List<String> groupsToRevert = new ArrayList<>(); + Either<List<String>, StorageOperationStatus> associatedGroups = groupOperation.getAssociatedGroupsToComponentInstance(componentInstanceId, true); + if (associatedGroups.isRight()) { + StorageOperationStatus status = associatedGroups.right().value(); + if (status != StorageOperationStatus.OK) { + BeEcompErrorManager.getInstance().logInternalFlowError("ChangeComponentInstanceVersion", "Failed to getch groups of current component instance", ErrorSeverity.ERROR); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return resultOp; + } + } else { + List<String> groups = associatedGroups.left().value(); + groupsToRevert.addAll(groups); + } + // rbetzer - before deleting component instance, retrieve env artifacts to keep track of artifactVersion + + Either<Map<String, ArtifactDefinition>, StorageOperationStatus> retrieveEnvArtifacts = componentInstanceOperation.fetchCIEnvArtifacts(componentInstanceId); + if (retrieveEnvArtifacts.isLeft()) + newComponentInstance.setDeploymentArtifacts(retrieveEnvArtifacts.left().value()); + else if (retrieveEnvArtifacts.right().value() != StorageOperationStatus.OK) { + log.debug("falied to fetch instance deployment artifacts {}", componentInstanceId ); + } + + resultOp = deleteComponentInstance(containerComponentId, componentInstanceId, containerComponentType); + if (resultOp.isRight()) { + + log.debug("failed to delete resource instance {}", resourceId); + + return resultOp; + + } + + Either<Component, ResponseFormat> eitherResourceName = getOriginComponentNameFromComponentInstance(newComponentInstance, true); + + if (eitherResourceName.isRight()) { + resultOp = Either.right(eitherResourceName.right().value()); + return resultOp; + } + + Component origComponent = eitherResourceName.left().value(); + + ComponentInstance resResourceInfo = resultOp.left().value(); + newComponentInstance.setName(resResourceInfo.getName()); + newComponentInstance.setPosX(resResourceInfo.getPosX()); + newComponentInstance.setPosY(resResourceInfo.getPosY()); + newComponentInstance.setDescription(resResourceInfo.getDescription()); + + resultOp = createComponentInstanceOnGraph(containerComponent, origComponent, newComponentInstance, userId, containerOperation, true); + + if (resultOp.isRight()) { + + log.debug("failed to create resource instance {}", resourceId); + + return resultOp; + + } + + newComponentInstance = resultOp.left().value(); + newComponentInstance.setName(resResourceInfo.getName()); + resultOp = updateComponentInstance(containerComponentId, containerComponentType, origComponent, newComponentInstance.getUniqueId(), newComponentInstance, true); + + ComponentInstance updatedComponentInstance = resultOp.left().value(); + if (resultOp.isRight()) { + log.debug("failed to create resource instance {}", resourceId); + return resultOp; + } + + if (false == groupsToRevert.isEmpty()) { + StorageOperationStatus associatedGroupsToComponentInstance = groupOperation.associateGroupsToComponentInstance(groupsToRevert, updatedComponentInstance.getUniqueId(), updatedComponentInstance.getName(), true); + if (associatedGroupsToComponentInstance != StorageOperationStatus.OK) { + BeEcompErrorManager.getInstance().logInternalFlowError("ChangeComponentInstanceVersion", "Failed to associate groups to new component instance", ErrorSeverity.ERROR); + resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return resultOp; + } + } + + Either<ComponentInstance, StorageOperationStatus> fullResourceInstance = componentInstanceOperation.getFullComponentInstance(resultOp.left().value(), getNodeTypeOfComponentInstanceOrigin()); + if (fullResourceInstance.isRight()) { + resultOp = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(fullResourceInstance.right().value()), resourceId)); + return resultOp; + } + resultOp = Either.left(fullResourceInstance.left().value()); + return resultOp; + + } finally { + unlockComponent(resultOp, containerComponent); + } + } + + protected abstract Either<Boolean, ResponseFormat> validateAllowedToContainCompInstances(org.openecomp.sdc.be.model.Component containerComponent); + + protected abstract NodeTypeEnum getNodeTypeOfComponentInstanceOrigin(); + + protected abstract ComponentTypeEnum getComponentTypeOfComponentInstance(); + + protected abstract ComponentOperation getContainerComponentOperation(); + + protected abstract ComponentOperation getCompInstOriginComponentOperation(); + + protected void validateIncrementCounter(String resourceInstanceId, GraphPropertiesDictionary counterType, Wrapper<Integer> instaceCounterWrapper, Wrapper<ResponseFormat> errorWrapper) { + Either<Integer, StorageOperationStatus> counterRes = componentInstanceOperation.increaseAndGetResourceInstanceSpecificCounter(resourceInstanceId, counterType, true); + + if (counterRes.isRight()) { + log.debug("increase And Get {} failed resource instance {}", counterType.name(), resourceInstanceId); + StorageOperationStatus status = counterRes.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status); + errorWrapper.setInnerElement(componentsUtils.getResponseFormat(actionStatus)); + } else { + instaceCounterWrapper.setInnerElement(counterRes.left().value()); + } + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CompositionBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CompositionBusinessLogic.java new file mode 100644 index 0000000000..6cebc7dd53 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CompositionBusinessLogic.java @@ -0,0 +1,285 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +/** + * This class holds the logic of arranging resource instance on the canvas for imported VF + * + * @author mshitrit + * + */ +@Component("compositionBusinessLogic") +public class CompositionBusinessLogic { + @Autowired + private VFComponentInstanceBusinessLogic vfComponentInstanceBusinessLogic; + + private static final int VFC_CANVAS_ELEMENT_SIZE = 50; + private static final int CP_CANVAS_ELEMENT_SIZE = 21; + private static final int CANVAS_WIDTH = 1000; + private static final int CANVAS_HEIGHT = 700; + private static final int SPACE_BETWEEN_ELEMENTS = VFC_CANVAS_ELEMENT_SIZE * 4; + private static final double CP_RADIUS_FACTOR = 0.4; + + enum RelativePosition { + LEFT, RIGHT, UP, DOWN + }; + + protected Either<List<ComponentInstance>, ResponseFormat> setPositionsForComponentInstances(Resource resource, String userId) { + Either<List<ComponentInstance>, ResponseFormat> result = Either.left(resource.getComponentInstances()); + + boolean isNotAllPositionsCalculated = resource.getComponentInstances() == null + || resource.getComponentInstances().stream().filter(p -> (p.getPosX() == null || p.getPosX().isEmpty()) || (p.getPosY() == null || p.getPosY().isEmpty())).findAny().isPresent(); + + if (isNotAllPositionsCalculated) { + // Arrange Icons In Spiral Pattern + Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations = buildSpiralPatternPositioningForComponentInstances(resource); + + // Set Relative Locations According to Canvas Size + componentInstanceLocations.entrySet().stream().forEach(e -> setRelativePosition(e)); + + // Update in DB + result = vfComponentInstanceBusinessLogic.updateComponentInstance(ComponentTypeEnum.RESOURCE_PARAM_NAME, resource.getUniqueId(), userId, resource.getComponentInstances(), false, false); + + } + return result; + + } + + private void setRelativePosition(Entry<ImmutablePair<Double, Double>, ComponentInstance> entry) { + int xCenter = CANVAS_WIDTH / 2; + int yCenter = CANVAS_HEIGHT / 2; + + ImmutablePair<Double, Double> matrixPosition = entry.getKey(); + ComponentInstance componentInstance = entry.getValue(); + componentInstance.setPosX(calculateCompositionPosition(xCenter, matrixPosition.getLeft(), componentInstance)); + componentInstance.setPosY(calculateCompositionPosition(yCenter, matrixPosition.getRight(), componentInstance)); + } + + private String calculateCompositionPosition(int center, double relativePosition, ComponentInstance componentInstance) { + final double topLeftCanvasPosition = center + relativePosition * CompositionBusinessLogic.SPACE_BETWEEN_ELEMENTS; + double offsetedCanvasPosition; + switch (componentInstance.getOriginType()) { + case CP: + offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.CP_CANVAS_ELEMENT_SIZE / 2; + break; + case VL: + offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.CP_CANVAS_ELEMENT_SIZE / 2; + break; + case VF: + offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2; + break; + case VFC: + offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2; + break; + default: + offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2; + break; + } + return String.valueOf(offsetedCanvasPosition); + } + + protected Map<ImmutablePair<Double, Double>, ComponentInstance> buildSpiralPatternPositioningForComponentInstances(Resource resource) { + + Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations = new HashMap<>(); + + List<ComponentInstance> componentInstances = new ArrayList<>(); + componentInstances.addAll(resource.getComponentInstances()); + Map<ComponentInstance, List<ComponentInstance>> connectededCps = getCpsConnectedToVFC(componentInstances, resource); + // Remove all cp that are connected from the list + componentInstances.removeAll(connectededCps.values().stream().flatMap(e -> e.stream()).collect(Collectors.toList())); + + buildSpiralPatternForMajorComponents(componentInstanceLocations, componentInstances); + buildCirclePatternForCps(componentInstanceLocations, connectededCps); + + return componentInstanceLocations; + } + + protected void buildCirclePatternForCps(Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstLocations, Map<ComponentInstance, List<ComponentInstance>> connectedCps) { + + for (Entry<ComponentInstance, List<ComponentInstance>> vfcCpList : connectedCps.entrySet()) { + Entry<ImmutablePair<Double, Double>, ComponentInstance> vfcOfTheCps = componentInstLocations.entrySet().stream().filter(p -> p.getValue().getUniqueId().equals(vfcCpList.getKey().getUniqueId())).findAny().get(); + buildCirclePatternForOneGroupOfCps(vfcOfTheCps.getKey(), vfcCpList.getValue(), componentInstLocations); + } + + } + + private void buildCirclePatternForOneGroupOfCps(ImmutablePair<Double, Double> vfcLocation, List<ComponentInstance> cpsGroup, Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstLocations) { + final int numberOfCps = cpsGroup.size(); + double angleBetweenCps = (!cpsGroup.isEmpty()) ? Math.toRadians(360) / numberOfCps : 0; + double currentAngle = 0; + Double xCenter = vfcLocation.getLeft(); + Double yCenter = vfcLocation.getRight(); + for (ComponentInstance currCp : cpsGroup) { + double cpXposition = xCenter + CompositionBusinessLogic.CP_RADIUS_FACTOR * Math.cos(currentAngle); + double cpYposition = yCenter + CompositionBusinessLogic.CP_RADIUS_FACTOR * Math.sin(currentAngle); + componentInstLocations.put(new ImmutablePair<Double, Double>(cpXposition, cpYposition), currCp); + currentAngle += angleBetweenCps; + } + + } + + private void buildSpiralPatternForMajorComponents(Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations, List<ComponentInstance> componentInstances) { + int elementsCounter = 0; + ImmutablePair<Double, Double> currPlacement; + ImmutablePair<Double, Double> prevPlacement = null; + RelativePosition relationToPrevElement = null; + for (ComponentInstance curr : componentInstances) { + elementsCounter++; + if (elementsCounter == 1) { + currPlacement = new ImmutablePair<Double, Double>(0D, 0D); + } else if (elementsCounter == 2) { + currPlacement = new ImmutablePair<Double, Double>(-1D, 0D); + relationToPrevElement = RelativePosition.LEFT; + } else { + relationToPrevElement = getRelativePositionForCurrentElement(componentInstanceLocations, relationToPrevElement, prevPlacement); + currPlacement = getRelativeElementLocation(prevPlacement, relationToPrevElement); + + } + + componentInstanceLocations.put(currPlacement, curr); + prevPlacement = currPlacement; + } + } + + protected Map<ComponentInstance, List<ComponentInstance>> getCpsConnectedToVFC(List<ComponentInstance> allComponentInstances, Resource vf) { + Map<ComponentInstance, List<ComponentInstance>> vfcWithItsCps = new HashMap<>(); + List<RequirementCapabilityRelDef> allRelations = vf.getComponentInstancesRelations(); + for (ComponentInstance curr : allComponentInstances) { + // Filters Only CPs + if (curr.getOriginType() == OriginTypeEnum.CP) { + // List Of elements the CP is connected to + List<RequirementCapabilityRelDef> connectedToList = allRelations.stream().filter(p -> p.getFromNode().equals(curr.getUniqueId()) || p.getToNode().equals(curr.getUniqueId())).collect(Collectors.toList()); + // Adds Only CPs Which are connected to VFC + filterCpConnectedToVFC(allComponentInstances, vfcWithItsCps, curr, connectedToList); + } + } + return vfcWithItsCps; + } + + private void filterCpConnectedToVFC(List<ComponentInstance> allComponentInstances, Map<ComponentInstance, List<ComponentInstance>> vfcWithItsCps, ComponentInstance currCP, List<RequirementCapabilityRelDef> connectedToTheCPList) { + if (!connectedToTheCPList.isEmpty()) { + // Set Of Ids Of components Instances which are connected certain CP + Set<String> mateIds = connectedToTheCPList.stream().map(cpRelation -> cpRelation.getFromNode().equals(currCP.getUniqueId()) ? cpRelation.getToNode() : cpRelation.getFromNode()).collect(Collectors.toSet()); + + // Vfc Component instance Connected to the CP + Optional<ComponentInstance> optionalVfcConnectedToCP = allComponentInstances.stream(). + // All instances connected to CP + filter(p -> mateIds.contains(p.getUniqueId())). + // Filter in only VFC connected to the CP + filter(p -> p.getOriginType() == OriginTypeEnum.VFC).findAny(); + + if (optionalVfcConnectedToCP.isPresent()) { + final ComponentInstance vfcWithCps = optionalVfcConnectedToCP.get(); + if (vfcWithItsCps.containsKey(vfcWithCps)) { + vfcWithItsCps.get(vfcWithCps).add(currCP); + } else { + List<ComponentInstance> cpsList = new ArrayList<>(); + cpsList.add(currCP); + vfcWithItsCps.put(vfcWithCps, cpsList); + } + } + } + } + + private RelativePosition getRelativePositionForCurrentElement(Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations, RelativePosition relationToPrevElement, ImmutablePair<Double, Double> prevPlacement) { + switch (relationToPrevElement) { + case LEFT: { + boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.UP, componentInstanceLocations); + relationToPrevElement = isOccupied ? RelativePosition.LEFT : RelativePosition.UP; + break; + } + case RIGHT: { + boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.DOWN, componentInstanceLocations); + relationToPrevElement = isOccupied ? RelativePosition.RIGHT : RelativePosition.DOWN; + break; + } + case UP: { + boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.RIGHT, componentInstanceLocations); + relationToPrevElement = isOccupied ? RelativePosition.UP : RelativePosition.RIGHT; + break; + } + case DOWN: { + boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.LEFT, componentInstanceLocations); + relationToPrevElement = isOccupied ? RelativePosition.DOWN : RelativePosition.LEFT; + break; + } + default: { + throw new UnsupportedOperationException(); + } + } + return relationToPrevElement; + } + + private boolean isAdjacentElementOccupied(ImmutablePair<Double, Double> currElement, RelativePosition adjacentElementRelationToCurrElement, Map<ImmutablePair<Double, Double>, ComponentInstance> allElements) { + + ImmutablePair<Double, Double> adjacentElementPosition = getRelativeElementLocation(currElement, adjacentElementRelationToCurrElement); + return allElements.containsKey(adjacentElementPosition); + } + + private ImmutablePair<Double, Double> getRelativeElementLocation(ImmutablePair<Double, Double> currElement, RelativePosition relativeLocation) { + ImmutablePair<Double, Double> relativeElementPosition; + switch (relativeLocation) { + + case LEFT: { + relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft() - 1, currElement.getRight()); + break; + } + case RIGHT: { + relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft() + 1, currElement.getRight()); + break; + } + case UP: { + relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft(), currElement.getRight() + 1); + break; + } + case DOWN: { + relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft(), currElement.getRight() - 1); + break; + } + default: { + throw new UnsupportedOperationException(); + } + } + return relativeElementPosition; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ConsumerBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ConsumerBusinessLogic.java new file mode 100644 index 0000000000..226225a07c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ConsumerBusinessLogic.java @@ -0,0 +1,313 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.Date; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ConsumerDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ConsumerOperation; +import org.openecomp.sdc.be.resources.data.ConsumerData; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.IUserBusinessLogic; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("ConsumerBusinessLogic") +public class ConsumerBusinessLogic extends BaseBusinessLogic { + + private static final String CONSUMER_NAME = "Consumer name"; + private static final String CONSUMER_SALT = "Consumer salt"; + private static final String CONSUMER_PW = "Consumer password"; + + @javax.annotation.Resource + private IUserBusinessLogic userAdmin; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + @javax.annotation.Resource + private ConsumerOperation consumerOperation; + + @javax.annotation.Resource + private IGraphLockOperation graphLockOperation; + + private static Logger log = LoggerFactory.getLogger(ConsumerBusinessLogic.class.getName()); + + public Either<ConsumerDefinition, ResponseFormat> createConsumer(User user, ConsumerDefinition consumer) { + + Either<User, ResponseFormat> userValidation = validateUser(user, consumer, AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS); + + if (userValidation.isRight()) { + return Either.right(userValidation.right().value()); + } + checkFieldsForOverrideAttempt(consumer); + user = userValidation.left().value(); + consumer.setLastModfierAtuid(user.getUserId()); + + Either<ConsumerDefinition, ResponseFormat> consumerValidationResponse = validateConsumer(consumer, user, AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS); + if (consumerValidationResponse.isRight()) { + ResponseFormat responseFormat = consumerValidationResponse.right().value(); + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS, consumer, responseFormat, user); + return Either.right(responseFormat); + } + String consumerName = consumer.getConsumerName(); + StorageOperationStatus lockResult = graphLockOperation.lockComponent(consumerName, NodeTypeEnum.ConsumerCredentials); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedLockObjectError, "createConsumer"); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError("createConsumer", NodeTypeEnum.ConsumerCredentials.getName(), consumerName); + log.debug("Failed to lock consumer {} error - {}", consumerName, lockResult); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS, consumer, responseFormat, user); + return Either.right(responseFormat); + } + try { + Either<ConsumerData, StorageOperationStatus> getResponse = consumerOperation.getCredentials(consumerName); + if (getResponse.isLeft() && getResponse.left().value() != null) { + return updateConsumer(consumer, user, true); + } + + Date date = new Date(); + consumer.setConsumerDetailsLastupdatedtime(date.getTime()); + consumer.setConsumerLastAuthenticationTime(Long.valueOf(0)); + + Either<ConsumerData, StorageOperationStatus> createResponse = consumerOperation.createCredentials(new ConsumerData(consumer)); + + if (createResponse.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponseForConsumer(createResponse.right().value())); + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS, consumer, responseFormat, user); + return Either.right(responseFormat); + } + log.debug("Consumer created successfully!!!"); + consumer = new ConsumerDefinition(createResponse.left().value().getConsumerDataDefinition()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS, consumer, responseFormat, user); + return Either.left(consumer); + } finally { + graphLockOperation.unlockComponent(consumerName, NodeTypeEnum.ConsumerCredentials); + } + } + + private Either<User, ResponseFormat> validateUser(User user, ConsumerDefinition consumer, AuditingActionEnum auditAction) { + + if (user.getUserId() == null || user.getUserId().trim().isEmpty()) { + log.debug("createEcompUser method - user is missing. userId={}", user.getUserId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + log.debug("audit before sending response"); + componentsUtils.auditConsumerCredentialsEvent(auditAction, consumer, responseFormat, user); + return Either.right(responseFormat); + } + log.debug("get user from DB"); + Either<User, ActionStatus> eitherCreator = userAdmin.getUser(user.getUserId(), false); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + log.debug("createEcompUser method - user is not listed. userId={}", user.getUserId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_ACCESS); + log.debug("audit before sending response"); + componentsUtils.auditConsumerCredentialsEvent(auditAction, consumer, responseFormat, user); + return Either.right(responseFormat); + } + + user = eitherCreator.left().value(); + // validate user role + log.debug("validate user role"); + if (!user.getRole().equals(Role.ADMIN.name())) { + log.info("role {} is not allowed to perform this action", user.getRole()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + log.debug("audit before sending response"); + componentsUtils.auditConsumerCredentialsEvent(auditAction, consumer, responseFormat, user); + return Either.right(responseFormat); + } + return Either.left(user); + } + + private Either<ConsumerDefinition, ResponseFormat> validateConsumer(ConsumerDefinition consumer, User user, AuditingActionEnum audatingAction) { + Either<ConsumerDefinition, ResponseFormat> validateConsumerName = validateConsumerName(consumer); + if (validateConsumerName.isRight()) { + return Either.right(validateConsumerName.right().value()); + } + Either<ConsumerDefinition, ResponseFormat> validateConsumerPassword = validateConsumerPassword(consumer); + if (validateConsumerPassword.isRight()) { + return Either.right(validateConsumerPassword.right().value()); + } + consumer = validateConsumerPassword.left().value(); + Either<ConsumerDefinition, ResponseFormat> validateEcompUserSalt = validateConsumerSalt(consumer); + if (validateEcompUserSalt.isRight()) { + return Either.right(validateEcompUserSalt.right().value()); + } + return Either.left(consumer); + + } + + private Either<ConsumerDefinition, ResponseFormat> validateConsumerName(ConsumerDefinition consumer) { + String name = consumer.getConsumerName(); + if (!ValidationUtils.validateStringNotEmpty(name)) { + log.debug("Consumer name cannot be empty."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, CONSUMER_NAME)); + } + if (!ValidationUtils.validateConsumerName(name)) { + log.debug("Consumer name is invalid."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT_PARAM, CONSUMER_NAME)); + } + if (!ValidationUtils.validateLength(name, ValidationUtils.CONSUMER_NAME_MAX_LENGTH)) { + log.debug("Consumer name exceeds limit."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, CONSUMER_NAME, String.valueOf(ValidationUtils.CONSUMER_NAME_MAX_LENGTH))); + } + if (!ValidationUtils.isUTF8Str(name)) { + log.debug("Consumer name includes non UTF 8 characters."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT_PARAM, CONSUMER_NAME)); + } + + return Either.left(consumer); + } + + private Either<ConsumerDefinition, ResponseFormat> validateConsumerPassword(ConsumerDefinition consumer) { + String password = consumer.getConsumerPassword(); + if (!ValidationUtils.validateStringNotEmpty(password)) { + log.debug("Consumer password cannot be empty."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, CONSUMER_PW)); + } + if (password.length() != ValidationUtils.CONSUMER_PASSWORD_LENGTH) { + log.debug("Consumer password length is not valid."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_LENGTH, CONSUMER_PW)); + } + consumer.setConsumerPassword(password.toLowerCase()); + if (!ValidationUtils.validateConsumerPassSalt(consumer.getConsumerPassword())) { + log.debug("Consumer password is invalid."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT_PARAM, CONSUMER_PW)); + } + + return Either.left(consumer); + } + + private Either<ConsumerDefinition, ResponseFormat> validateConsumerSalt(ConsumerDefinition consumer) { + String salt = consumer.getConsumerSalt(); + if (!ValidationUtils.validateStringNotEmpty(salt)) { + log.debug("Consumer salt cannot be empty."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_DATA, CONSUMER_SALT)); + } + if (salt.length() != ValidationUtils.CONSUMER_SALT_LENGTH) { + log.debug("Consumer salt length is not valid."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_LENGTH, CONSUMER_SALT)); + } + if (!ValidationUtils.validateConsumerPassSalt(salt)) { + log.debug("Consumer salt is invalid."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT_PARAM, CONSUMER_SALT)); + } + + return Either.left(consumer); + } + + public Either<ConsumerDefinition, ResponseFormat> getConsumer(String consumerId, User user) { + ConsumerDefinition tmpConsumer = new ConsumerDefinition(); + tmpConsumer.setConsumerName(consumerId); + // In case of filter (southbound) call + if (user != null) { + Either<User, ResponseFormat> userValidation = validateUser(user, tmpConsumer, AuditingActionEnum.GET_ECOMP_USER_CREDENTIALS); + if (userValidation.isRight()) { + return Either.right(userValidation.right().value()); + } + user = userValidation.left().value(); + } + Either<ConsumerData, StorageOperationStatus> getResult = consumerOperation.getCredentials(consumerId); + if (getResult.isRight()) { + ActionStatus action = componentsUtils.convertFromStorageResponseForConsumer(getResult.right().value()); + ResponseFormat responseFormat; + if (action == ActionStatus.ECOMP_USER_NOT_FOUND) { + responseFormat = componentsUtils.getResponseFormat(action, consumerId); + } else { + responseFormat = componentsUtils.getResponseFormat(action); + } + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.GET_ECOMP_USER_CREDENTIALS, tmpConsumer, responseFormat, user); + return Either.right(responseFormat); + } + ConsumerDefinition consumer = new ConsumerDefinition(getResult.left().value().getConsumerDataDefinition()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.GET_ECOMP_USER_CREDENTIALS, consumer, responseFormat, user); + return Either.left(consumer); + } + + public Either<ConsumerDefinition, ResponseFormat> getConsumer(String consumerId) { + return getConsumer(consumerId, null); + } + + public Either<ConsumerDefinition, ResponseFormat> deleteConsumer(String consumerId, User user) { + ConsumerDefinition tmpConsumer = new ConsumerDefinition(); + tmpConsumer.setConsumerName(consumerId); + Either<User, ResponseFormat> userValidation = validateUser(user, tmpConsumer, AuditingActionEnum.DELETE_ECOMP_USER_CREDENTIALS); + if (userValidation.isRight()) { + return Either.right(userValidation.right().value()); + } + user = userValidation.left().value(); + Either<ConsumerData, StorageOperationStatus> deleteResult = consumerOperation.deleteCredentials(consumerId); + if (deleteResult.isRight()) { + ActionStatus action = componentsUtils.convertFromStorageResponseForConsumer(deleteResult.right().value()); + ResponseFormat responseFormat; + if (action == ActionStatus.ECOMP_USER_NOT_FOUND) { + responseFormat = componentsUtils.getResponseFormat(action, consumerId); + } else { + responseFormat = componentsUtils.getResponseFormat(action); + } + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.DELETE_ECOMP_USER_CREDENTIALS, tmpConsumer, responseFormat, user); + return Either.right(responseFormat); + } + ConsumerDefinition consumer = new ConsumerDefinition(deleteResult.left().value().getConsumerDataDefinition()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + componentsUtils.auditConsumerCredentialsEvent(AuditingActionEnum.DELETE_ECOMP_USER_CREDENTIALS, consumer, responseFormat, user); + return Either.left(consumer); + } + + public Either<ConsumerDefinition, ResponseFormat> updateConsumer(ConsumerDefinition consumer, User modifier, boolean isCreateRequest) { + Either<ConsumerData, StorageOperationStatus> updateResult = consumerOperation.updateCredentials(new ConsumerData(consumer)); + if (updateResult.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponseForConsumer(updateResult.right().value())); + return Either.right(responseFormat); + } + consumer = new ConsumerDefinition(updateResult.left().value().getConsumerDataDefinition()); + return Either.left(consumer); + } + + private void checkFieldsForOverrideAttempt(ConsumerDefinition consumer) { + if (consumer.getConsumerDetailsLastupdatedtime() != null) { + log.info("Consumer Details Last updated time cannot be defined by user. This field will be overridden by the application"); + } + if (consumer.getConsumerLastAuthenticationTime() != null) { + log.info("Consumer Last Authentication time cannot be defined by user. This field will be overridden by the application"); + } + if (consumer.getLastModfierAtuid() != null) { + log.info("Consumer Last Modifier USER_ID cannot be defined by user. This field will be overridden by the application"); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java new file mode 100644 index 0000000000..badb257a80 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class CsarValidationUtils { + + private static Logger log = LoggerFactory.getLogger(CsarValidationUtils.class.getName()); + + private static final String TOSCA_META_FILE_VERSION = "TOSCA-Meta-File-Version"; + + private static final String CSAR_VERSION = "CSAR-Version"; + + private static final String CREATED_BY = "Created-By"; + + private static final String NEW_LINE_DELM = "\n"; + + public final static String TOSCA_METADATA_FILE = "TOSCA-Metadata/TOSCA.meta"; + + public static final String TOSCA_META_ENTRY_DEFINITIONS = "Entry-Definitions"; + + public final static String[] TOSCA_METADATA_FIELDS = { TOSCA_META_FILE_VERSION, CSAR_VERSION, CREATED_BY, TOSCA_META_ENTRY_DEFINITIONS }; + + public final static String ARTIFACTS_METADATA_FILE = "HEAT.meta"; + + public final static String ARTIFACTS = "Artifacts/"; + + public static final String TOSCA_CSAR_EXTENSION = ".csar"; + + public static Either<Boolean, ResponseFormat> validateCsar(Map<String, byte[]> csar, String csarUUID, ComponentsUtils componentsUtils) { + Either<Boolean, ResponseFormat> validateStatus = validateIsTOSCAMetadataExist(csar, csarUUID, componentsUtils); + if (validateStatus.isRight()) { + return Either.right(validateStatus.right().value()); + } + log.trace("TOSCA-Metadata/TOSCA.meta file found, CSAR id {}", csarUUID); + return validateTOSCAMetadataFile(csar, csarUUID, componentsUtils); + + } + + public static Either<ImmutablePair<String, String>, ResponseFormat> getToscaYaml(Map<String, byte[]> csar, String csarUUID, ComponentsUtils componentsUtils) { + Either<Boolean, ResponseFormat> validateStatus = validateIsTOSCAMetadataExist(csar, csarUUID, componentsUtils); + if (validateStatus.isRight()) { + return Either.right(validateStatus.right().value()); + } + byte[] toscaMetaBytes = csar.get(TOSCA_METADATA_FILE); + Properties props = new Properties(); + try { + props.load(new ByteArrayInputStream(toscaMetaBytes)); + } catch (IOException e) { + log.debug("TOSCA-Metadata/TOSCA.meta file is not in expected key-value form in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, csarUUID)); + } + + String yamlFileName = props.getProperty(TOSCA_META_ENTRY_DEFINITIONS); + + if (!csar.containsKey(yamlFileName)) { + log.debug("Entry-Definitions entry not found in TOSCA-Metadata/TOSCA.meta file, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("Entry-Definitions entry not found in TOSCA-Metadata/TOSCA.meta file in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.YAML_NOT_FOUND_IN_CSAR, csarUUID, yamlFileName)); + } + + log.trace("Found Entry-Definitions property in TOSCA-Metadata/TOSCA.meta, Entry-Definitions: {}, CSAR id: {}", yamlFileName, csarUUID); + byte[] yamlFileBytes = csar.get(yamlFileName); + if (yamlFileBytes == null) { + log.debug("Entry-Definitions {} file not found in csar, csar ID {}", yamlFileName, csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("Entry-Definitions " + yamlFileName + " file not found in CSAR with id " + csarUUID, "CSAR structure is invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.YAML_NOT_FOUND_IN_CSAR, csarUUID, yamlFileName)); + } + + String yamlFileContents = new String(yamlFileBytes); + + return Either.left(new ImmutablePair<String, String>(yamlFileName, yamlFileContents)); + } + + public static Either<ImmutablePair<String, String>, ResponseFormat> getArtifactsMeta(Map<String, byte[]> csar, String csarUUID, ComponentsUtils componentsUtils) { + + if (!csar.containsKey(ARTIFACTS + ARTIFACTS_METADATA_FILE)) { + log.debug("Entry-Definitions entry not found in TOSCA-Metadata/TOSCA.meta file, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("Entry-Definitions entry not found in TOSCA-Metadata/TOSCA.meta file in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.YAML_NOT_FOUND_IN_CSAR, csarUUID, ARTIFACTS_METADATA_FILE)); + } + + log.trace("Found Entry-Definitions property in TOSCA-Metadata/TOSCA.meta, Entry-Definitions: {}, CSAR id: {}", ARTIFACTS_METADATA_FILE, csarUUID); + byte[] artifactsMetaBytes = csar.get(ARTIFACTS + ARTIFACTS_METADATA_FILE); + if (artifactsMetaBytes == null) { + log.debug("Entry-Definitions {} file not found in csar, csar ID {}", ARTIFACTS + ARTIFACTS_METADATA_FILE, csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("Entry-Definitions " + ARTIFACTS + ARTIFACTS_METADATA_FILE + " file not found in CSAR with id " + csarUUID, "CSAR structure is invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.YAML_NOT_FOUND_IN_CSAR, csarUUID, ARTIFACTS + ARTIFACTS_METADATA_FILE)); + } + + String artifactsFileContents = new String(artifactsMetaBytes); + + return Either.left(new ImmutablePair<String, String>(ARTIFACTS + ARTIFACTS_METADATA_FILE, artifactsFileContents)); + } + + public static Either<ImmutablePair<String, byte[]>, ResponseFormat> getArtifactsContent(String csarUUID, Map<String, byte[]> csar, String artifactName, ComponentsUtils componentsUtils) { + if (!csar.containsKey(ARTIFACTS + artifactName)) { + log.debug("Entry-Definitions entry not found in Artifacts/HEAT.meta file, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("Entry-Definitions entry not found in TOSCA-Metadata/TOSCA.meta file in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND_IN_CSAR, ARTIFACTS + artifactName, csarUUID)); + } + + log.trace("Found Entry-Definitions property in Artifacts/HEAT.meta, Entry-Definitions: {}, CSAR id: {}", ARTIFACTS + artifactName, csarUUID); + byte[] artifactFileBytes = csar.get(ARTIFACTS + artifactName); + if (artifactFileBytes == null) { + log.debug("Entry-Definitions {} file not found in csar, csar ID {}", ARTIFACTS + artifactName, csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("Entry-Definitions " + ARTIFACTS + artifactName + " file not found in CSAR with id " + csarUUID, "CSAR structure is invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND_IN_CSAR, ARTIFACTS + artifactName, csarUUID)); + } + + return Either.left(new ImmutablePair<String, byte[]>(artifactName, artifactFileBytes)); + } + + private static Either<Boolean, ResponseFormat> validateTOSCAMetadataFile(Map<String, byte[]> csar, String csarUUID, ComponentsUtils componentsUtils) { + + byte[] toscaMetaBytes = csar.get(TOSCA_METADATA_FILE); + String toscaMetadata = new String(toscaMetaBytes); + String[] splited = toscaMetadata.split(NEW_LINE_DELM); + if (splited == null || splited.length < TOSCA_METADATA_FIELDS.length) { + log.debug("TOSCA-Metadata/TOSCA.meta file is not in expected key-value form in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, csarUUID)); + } + /* + * if(splited.length == TOSCA_METADATA_FIELDS.length){ if(!toscaMetadata.endsWith(NEW_LINE_DELM)){ log. debug("TOSCA-Metadata/TOSCA.meta file is not in expected key-value form in csar, csar ID {}" , csarUUID); + * BeEcompErrorManager.getInstance(). logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " +csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); return + * Either.right(componentsUtils.getResponseFormat(ActionStatus. CSAR_INVALID_FORMAT, csarUUID)); } } + */ + + Either<Boolean, ResponseFormat> block_0Status = validateBlock_0(csarUUID, splited, componentsUtils); + if (block_0Status.isRight()) { + return Either.right(block_0Status.right().value()); + } + + return Either.left(true); + + } + + private static Either<Boolean, ResponseFormat> validateBlock_0(String csarUUID, String[] splited, ComponentsUtils componentsUtils) { + int index = 0; + for (String toscaField : TOSCA_METADATA_FIELDS) { + + Properties props = new Properties(); + + try { + props.load(new ByteArrayInputStream(splited[index].getBytes())); + } catch (IOException e) { + log.debug("TOSCA-Metadata/TOSCA.meta file is not in expected key-value form in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, csarUUID)); + } + if (!props.containsKey(toscaField)) { + log.debug("TOSCA.meta file format is invalid: No new line after block_0 as expected in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, csarUUID)); + } + String value = props.getProperty(toscaField); + if (value == null || value.isEmpty()) { + log.debug("TOSCA-Metadata/TOSCA.meta file is not in expected key-value form in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, csarUUID)); + } + + // TOSCA-Meta-File-Version & CSAR-Version : digit.digit - format + // validation + if (toscaField.equals(TOSCA_META_FILE_VERSION) || toscaField.equals(CSAR_VERSION)) { + if (!validateTOSCAMetaProperty(value)) { + log.debug("TOSCA-Metadata/TOSCA.meta file contains {} in wrong format (digit.digit), csar ID {}", toscaField, csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not in expected key-value form in CSAR with id " + csarUUID, "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, csarUUID)); + } + } + index++; + } + return Either.left(true); + } + + private static boolean validateTOSCAMetaProperty(String toscaProperty) { + final String FLOAT_STRING = "^\\d{1}[.]\\d{1}$"; + final Pattern FLOAT_PATTERN = Pattern.compile(FLOAT_STRING); + + Matcher floatMatcher = FLOAT_PATTERN.matcher(toscaProperty); + return floatMatcher.matches(); + } + + private static Either<Boolean, ResponseFormat> validateIsTOSCAMetadataExist(Map<String, byte[]> csar, String csarUUID, ComponentsUtils componentsUtils) { + if (csar == null || csar.isEmpty()) { + log.debug("Error when fetching csar with ID {}", csarUUID); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Creating resource from CSAR: fetching CSAR with id " + csarUUID + " failed"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID, csarUUID); + return Either.right(responseFormat); + } + if (!csar.containsKey(TOSCA_METADATA_FILE)) { + log.debug("TOSCA-Metadata/TOSCA.meta file not found in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not found in CSAR with id " + csarUUID, "CSAR structure is invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID, csarUUID)); + } + byte[] toscaMetaBytes = csar.get(TOSCA_METADATA_FILE); + // Tal && exchanged for || + if (toscaMetaBytes == null || toscaMetaBytes.length == 0) { + log.debug("TOSCA-Metadata/TOSCA.meta file not found in csar, csar ID {}", csarUUID); + BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not found in CSAR with id " + csarUUID, "CSAR structure is invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID, csarUUID)); + } + + return Either.left(Boolean.TRUE); + } + + public static Either<String, ResponseFormat> getToscaYamlChecksum(Map<String, byte[]> csar, String csarUUID, ComponentsUtils componentsUtils) { + + Either<ImmutablePair<String, String>, ResponseFormat> toscaYamlRes = getToscaYaml(csar, csarUUID, componentsUtils); + if (toscaYamlRes.isRight() || toscaYamlRes.left().value() == null || toscaYamlRes.left().value().getRight() == null) { + log.debug("Faild to create toscaYamlChecksum for csar, csar ID {}", csarUUID); + return Either.right(toscaYamlRes.right().value()); + } + + String newCheckSum = GeneralUtility.calculateMD5ByByteArray(toscaYamlRes.left().value().getRight().getBytes()); + return Either.left(newCheckSum); + + } + + public static boolean isCsarPayloadName(String payloadName) { + if (payloadName == null) + return false; + return payloadName.toLowerCase().endsWith(TOSCA_CSAR_EXTENSION); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeImportManager.java new file mode 100644 index 0000000000..e5fba0dff5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeImportManager.java @@ -0,0 +1,255 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.CommonImportManager.ElementTypeEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("dataTypeImportManager") +public class DataTypeImportManager { + + public static void main(String[] args) { + + List<PropertyDefinition> properties = new ArrayList<>(); + PropertyDefinition propertyDefintion = new PropertyDefinition(); + propertyDefintion.setName("aaa"); + properties.add(propertyDefintion); + + List<String> allParentsProps = new ArrayList<>(); + allParentsProps.add("aaa"); + allParentsProps.add("bbb"); + + Set<String> alreadyExistPropsCollection = properties.stream().filter(p -> allParentsProps.contains(p.getName())).map(p -> p.getName()).collect(Collectors.toSet()); + System.out.println(alreadyExistPropsCollection); + + } + + private static Logger log = LoggerFactory.getLogger(DataTypeImportManager.class.getName()); + @Resource + private PropertyOperation propertyOperation; + @Resource + private ComponentsUtils componentsUtils; + @Resource + private CommonImportManager commonImportManager; + + public Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat> createDataTypes(String dataTypeYml) { + return commonImportManager.createElementTypes(dataTypeYml, elementTypeYml -> createDataTypesFromYml(elementTypeYml), elementTypesList -> createDataTypesByDao(elementTypesList), ElementTypeEnum.DataType); + } + + private Either<List<DataTypeDefinition>, ActionStatus> createDataTypesFromYml(String dataTypesYml) { + + return commonImportManager.createElementTypesFromYml(dataTypesYml, (dataTypeName, dataTypeJsonData) -> createDataType(dataTypeName, dataTypeJsonData)); + + } + + private Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat> createDataTypesByDao(List<DataTypeDefinition> dataTypesToCreate) { + + return commonImportManager.createElementTypesByDao(dataTypesToCreate, dataType -> validateDataType(dataType), dataType -> new ImmutablePair<>(ElementTypeEnum.DataType, dataType.getName()), + dataTypeName -> propertyOperation.getDataTypeByNameWithoutDerived(dataTypeName), dataType -> propertyOperation.addDataType(dataType), (newDataType, oldDataType) -> propertyOperation.updateDataType(newDataType, oldDataType)); + } + + private Either<ActionStatus, ResponseFormat> validateDataType(DataTypeDefinition dataType) { + + String dataTypeName = dataType.getName(); + List<PropertyDefinition> properties = dataType.getProperties(); + if (properties == null) { + // At least one parameter should be defined either in the properties + // section or at one of the parents + String derivedDataType = dataType.getDerivedFromName(); + // If there are no properties, then we can create a data type if it + // is an abstract one or it derives from non abstract data type + if ((derivedDataType == null || derivedDataType.isEmpty())) { + if (false == isAbstract(dataType.getName())) { + if (false == ToscaPropertyType.isScalarType(dataTypeName)) { + log.debug("Data type {} must have properties unless it derives from non abstract data type", dataType.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, dataType, null); + + return Either.right(responseFormat); + } + } + } else { + // if it is not a scalar data type and it derives from abstract + // data type, we should reject the request. + if (false == ToscaPropertyType.isScalarType(dataTypeName) && true == isAbstract(derivedDataType)) { + log.debug("Data type {} which derived from abstract data type must have at least one property", dataType.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, dataType, null); + + return Either.right(responseFormat); + } + } + } else { + // properties tag cannot be empty + if (properties.isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY, dataType, null); + + return Either.right(responseFormat); + } + + // check no duplicates + Set<String> collect = properties.stream().map(p -> p.getName()).collect(Collectors.toSet()); + if (collect != null) { + if (properties.size() != collect.size()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_DUPLICATE_PROPERTY, dataType, null); + + return Either.right(responseFormat); + } + } + + List<String> propertiesWithSameTypeAsDataType = properties.stream().filter(p -> p.getType().equals(dataType.getName())).map(p -> p.getName()).collect(Collectors.toList()); + if (propertiesWithSameTypeAsDataType != null && propertiesWithSameTypeAsDataType.isEmpty() == false) { + log.debug("The data type {} contains properties with the type {}", dataType.getName(), dataType.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE, dataType, propertiesWithSameTypeAsDataType); + + return Either.right(responseFormat); + } + } + + String derivedDataType = dataType.getDerivedFromName(); + if (derivedDataType != null) { + Either<DataTypeDefinition, StorageOperationStatus> derivedDataTypeByName = propertyOperation.getDataTypeByName(derivedDataType, true); + if (derivedDataTypeByName.isRight()) { + StorageOperationStatus status = derivedDataTypeByName.right().value(); + if (status == StorageOperationStatus.NOT_FOUND) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_DERIVED_IS_MISSING, dataType, null); + + return Either.right(responseFormat); + } else { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.GENERAL_ERROR, dataType, null); + + return Either.right(responseFormat); + + } + } else { + + DataTypeDefinition derivedDataTypeDef = derivedDataTypeByName.left().value(); + if (properties != null && properties.isEmpty() == false) { + + if (true == isScalarType(derivedDataTypeDef)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_CANNOT_HAVE_PROPERTIES, dataType, null); + + return Either.right(responseFormat); + } + + Set<String> allParentsProps = new HashSet<>(); + do { + List<PropertyDefinition> currentParentsProps = derivedDataTypeDef.getProperties(); + if (currentParentsProps != null) { + for (PropertyDefinition propertyDefinition : currentParentsProps) { + allParentsProps.add(propertyDefinition.getName()); + } + } + derivedDataTypeDef = derivedDataTypeDef.getDerivedFrom(); + } while (derivedDataTypeDef != null); + + // Check that no property is already defined in one of the + // ancestors + Set<String> alreadyExistPropsCollection = properties.stream().filter(p -> allParentsProps.contains(p.getName())).map(p -> p.getName()).collect(Collectors.toSet()); + if (alreadyExistPropsCollection != null && alreadyExistPropsCollection.isEmpty() == false) { + List<String> duplicateProps = new ArrayList<>(); + duplicateProps.addAll(alreadyExistPropsCollection); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR, dataType, duplicateProps); + + return Either.right(responseFormat); + } + + } + } + } + return Either.left(ActionStatus.OK); + } + + private boolean isAbstract(String dataTypeName) { + + ToscaPropertyType isPrimitiveToscaType = ToscaPropertyType.isValidType(dataTypeName); + + return isPrimitiveToscaType != null && isPrimitiveToscaType.isAbstract() == true; + + } + + private boolean isScalarType(DataTypeDefinition dataTypeDef) { + + boolean isScalar = false; + DataTypeDefinition dataType = dataTypeDef; + + while (dataType != null) { + + String name = dataType.getName(); + if (ToscaPropertyType.isScalarType(name)) { + isScalar = true; + break; + } + + dataType = dataType.getDerivedFrom(); + } + + return isScalar; + } + + private DataTypeDefinition createDataType(String dataTypeName, Map<String, Object> toscaJson) { + DataTypeDefinition dataType = new DataTypeDefinition(); + + dataType.setName(dataTypeName); + + if (toscaJson != null) { + // Description + final Consumer<String> descriptionSetter = description -> dataType.setDescription(description); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DESCRIPTION.getElementName(), descriptionSetter); + // Derived From + final Consumer<String> derivedFromSetter = derivedFrom -> dataType.setDerivedFromName(derivedFrom); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DERIVED_FROM.getElementName(), derivedFromSetter); + // Properties + commonImportManager.setProperties(toscaJson, (values) -> dataType.setProperties(values)); + + setConstraints(toscaJson, dataType); + } + return dataType; + } + + private void setConstraints(Map<String, Object> toscaJson, DataTypeDefinition dataType) { + // TODO Auto-generated method stub + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DistributionMonitoringBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DistributionMonitoringBusinessLogic.java new file mode 100644 index 0000000000..9d9425ea85 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DistributionMonitoringBusinessLogic.java @@ -0,0 +1,214 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; +import org.apache.http.HttpStatus; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.cassandra.AuditCassandraDao; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.info.DistributionStatusInfo; +import org.openecomp.sdc.be.info.DistributionStatusListResponse; +import org.openecomp.sdc.be.info.DistributionStatusOfServiceInfo; +import org.openecomp.sdc.be.info.DistributionStatusOfServiceListResponce; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.resources.data.auditing.AuditingGenericEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionStatusEvent; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.ESTimeBasedEvent; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component("distributionMonitoringBusinessLogic") +public class DistributionMonitoringBusinessLogic extends BaseBusinessLogic { + private static final String DEPLOYED = "Deployed"; + + private static final String ERROR = "Error"; + + private static final String DISTRIBUTED = "Distributed"; + + private static final String IN_PROGRESS = "In Progress"; + + private static Logger log = LoggerFactory.getLogger(ArtifactsBusinessLogic.class.getName()); + + // @javax.annotation.Resource + // private AuditingDao auditingDao; + + @Autowired + private AuditCassandraDao cassandraDao; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + public DistributionMonitoringBusinessLogic() { + } + + public Either<DistributionStatusListResponse, ResponseFormat> getListOfDistributionStatus(String did, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "get List Of Distribution Status", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + log.trace("getListOfDistributionStatus for did {}", did); + Either<List<DistributionStatusEvent>, ActionStatus> distributionStatus = cassandraDao.getListOfDistributionStatuses(did); + if (distributionStatus.isRight()) { + log.debug("not found distribution statuses for did {} status is {} ", did, distributionStatus.right().value()); + return Either.right(componentsUtils.getResponseFormat(distributionStatus.right().value(), did)); + } + List<DistributionStatusInfo> distribStatusInfoList = new ArrayList<DistributionStatusInfo>(); + List<DistributionStatusEvent> distributionStatusEventList = distributionStatus.left().value(); + if (distributionStatusEventList != null) { + for (ESTimeBasedEvent distributionStatusEvent : distributionStatusEventList) { + distribStatusInfoList.add(new DistributionStatusInfo(distributionStatusEvent)); + } + } + + DistributionStatusListResponse distributionStatusListResponse = new DistributionStatusListResponse(); + distributionStatusListResponse.setDistributionStatusList(distribStatusInfoList); + log.trace("list statuses for did {} is {} ", did, distribStatusInfoList); + return Either.left(distributionStatusListResponse); + } + + public Either<DistributionStatusOfServiceListResponce, ResponseFormat> getListOfDistributionServiceStatus(String serviceUuid, String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get List Of Distribution Service Status", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + log.trace("getListOfDistributionServiceStatus for serviceUUID {}", serviceUuid); + Either<List<? extends AuditingGenericEvent>, ActionStatus> status = cassandraDao.getServiceDistributionStatusesList(serviceUuid); + if (status.isRight()) { + log.debug("failed to find service distribution statuses. error: {}", status); + return Either.right(componentsUtils.getResponseFormat(status.right().value(), serviceUuid)); + } + List<DistributionStatusOfServiceInfo> distribStatusInfoList = new ArrayList<DistributionStatusOfServiceInfo>(); + List<? extends AuditingGenericEvent> distributionStatusEventList = status.left().value(); + distribStatusInfoList = handleAuditingDaoResponse(distributionStatusEventList); + DistributionStatusOfServiceListResponce distributionStatusListResponse = new DistributionStatusOfServiceListResponce(); + distributionStatusListResponse.setDistributionStatusOfServiceList(distribStatusInfoList); + return Either.left(distributionStatusListResponse); + } + + private List<DistributionStatusOfServiceInfo> handleAuditingDaoResponse(List<? extends AuditingGenericEvent> distribStatusInfoList) { + List<DistributionStatusOfServiceInfo> reslist = new ArrayList<DistributionStatusOfServiceInfo>(); + Map<String, List<AuditingGenericEvent>> serviceDidMap = createServiceDidMap(distribStatusInfoList); + Set<String> didSet = serviceDidMap.keySet(); + for (String did : didSet) { + DistributionStatusOfServiceInfo distributionStatusOfServiceInfo = new DistributionStatusOfServiceInfo(); + distributionStatusOfServiceInfo.setDistributionID(did); + String dReguestStatus = ""; + String dNotifyStatus = ""; + boolean isResult = false; + List<? extends AuditingGenericEvent> auditingGenericEventList = serviceDidMap.get(did); + ESTimeBasedEvent resAuditingGenericEvent = null; + for (AuditingGenericEvent auditingGenericEvent : auditingGenericEventList) { + auditingGenericEvent.fillFields(); + + String action = (String) auditingGenericEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_ACTION.getDisplayName()); + Object modifierUserId = auditingGenericEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID.getDisplayName()); + if (modifierUserId != null) { + distributionStatusOfServiceInfo.setUserId((String) modifierUserId); + } + + if (action.equals(AuditingActionEnum.DISTRIBUTION_DEPLOY.getName())) { + + isResult = true; + resAuditingGenericEvent = auditingGenericEvent; + break; + } else if (action.equals(AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_REQUEST.getName())) { + dReguestStatus = getStatusFromAuditEvent(auditingGenericEvent); + } else if (action.equals(AuditingActionEnum.DISTRIBUTION_NOTIFY.getName())) { + dNotifyStatus = getStatusFromAuditEvent(auditingGenericEvent); + } + + resAuditingGenericEvent = auditingGenericEvent; + + } + distributionStatusOfServiceInfo.setTimestamp((String) resAuditingGenericEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_TIMESTAMP.getDisplayName())); + + if (!isResult) { + if (dReguestStatus.equals(String.valueOf(HttpStatus.SC_OK))) { + if (dNotifyStatus.isEmpty()) { + distributionStatusOfServiceInfo.setDeployementStatus(IN_PROGRESS); + + } else { + if (dNotifyStatus.equals(String.valueOf(HttpStatus.SC_OK))) + distributionStatusOfServiceInfo.setDeployementStatus(DISTRIBUTED); + else + distributionStatusOfServiceInfo.setDeployementStatus(ERROR); + } + } else + distributionStatusOfServiceInfo.setDeployementStatus(ERROR); + } else + distributionStatusOfServiceInfo.setDeployementStatus(DEPLOYED); + reslist.add(distributionStatusOfServiceInfo); + } + + return reslist; + } + + private String getStatusFromAuditEvent(ESTimeBasedEvent auditingGenericEvent) { + String status = ""; + Object requestStatus = auditingGenericEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_STATUS.getDisplayName()); + if (requestStatus instanceof String) { + status = (String) requestStatus; + } + return status; + } + + private Map<String, List<AuditingGenericEvent>> createServiceDidMap(List<? extends AuditingGenericEvent> distribStatusInfoList) { + + Map<String, List<AuditingGenericEvent>> serviceDidMap = new HashMap<String, List<AuditingGenericEvent>>(); + for (AuditingGenericEvent auditingGenericEvent : distribStatusInfoList) { + List<AuditingGenericEvent> auditingGenericEventList = null; + String did = ""; + auditingGenericEvent.fillFields(); + + Object didValue = auditingGenericEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID.getDisplayName()); + if (didValue != null) { + did = (String) didValue; + } + + if (!did.isEmpty()) { + if (serviceDidMap.containsKey(did)) { + auditingGenericEventList = serviceDidMap.get(did); + } + if (auditingGenericEventList == null) { + auditingGenericEventList = new ArrayList(); + + } + auditingGenericEventList.add(auditingGenericEvent); + serviceDidMap.put(did, auditingGenericEventList); + } + } + return serviceDidMap; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java new file mode 100644 index 0000000000..5ebb86f1ba --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java @@ -0,0 +1,1125 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; +import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum; +import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactType; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.PropertyScope; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.Tag; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +@org.springframework.stereotype.Component("elementsBusinessLogic") +public class ElementBusinessLogic extends BaseBusinessLogic { + + private static Logger log = LoggerFactory.getLogger(ElementBusinessLogic.class.getName()); + + @javax.annotation.Resource + private IElementOperation elementOperation; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + @javax.annotation.Resource + private UserBusinessLogic userAdminManager; + + /** + * + * @param user + * @return + */ + public Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowed(User user) { + Either<Map<String, List<? extends Component>>, ResponseFormat> response = null; + // Getting the role + String role = user.getRole(); + String userId = null; + Role currentRole = Role.valueOf(role); + + switch (currentRole) { + case DESIGNER: + userId = user.getUserId(); + response = handleDesigner(userId); + break; + + case TESTER: + userId = user.getUserId(); + response = handleTester(userId); + break; + + case GOVERNOR: + userId = user.getUserId(); + response = handleGovernor(userId); + break; + + case OPS: + userId = user.getUserId(); + response = handleOps(userId); + break; + + case PRODUCT_STRATEGIST: + userId = user.getUserId(); + response = handleProductStrategist(userId); + break; + + case PRODUCT_MANAGER: + userId = user.getUserId(); + response = handleProductManager(userId); + break; + + case ADMIN: + response = handleAdmin(); + break; + + default: + response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + break; + } + return response; + + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleAdmin() { + Either<Map<String, List<? extends Component>>, ResponseFormat> response; + // userId should stay null + Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>(); + Set<LifecycleStateEnum> lastStateStates = new HashSet<LifecycleStateEnum>(); + lifecycleStates.add(LifecycleStateEnum.CERTIFIED); + response = getFollowedResourcesAndServices(null, lifecycleStates, lastStateStates); + return response; + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleDesigner(String userId) { + Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>(); + Set<LifecycleStateEnum> lastStateStates = new HashSet<LifecycleStateEnum>(); + Either<Map<String, List<? extends Component>>, ResponseFormat> response; + lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + lifecycleStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION); + lifecycleStates.add(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS); + lifecycleStates.add(LifecycleStateEnum.CERTIFIED); + // more states + lastStateStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION); + response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates); + return response; + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleGovernor(String userId) { + Either<Map<String, List<? extends Component>>, ResponseFormat> result = handleFollowedCertifiedServices(null); + return result; + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleProductStrategist(String userId) { + // Should be empty list according to Ella, 13/03/16 + Map<String, List<? extends Component>> result = new HashMap<String, List<? extends Component>>(); + result.put("products", new ArrayList<>()); + return Either.left(result); + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleProductManager(String userId) { + Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>(); + Set<LifecycleStateEnum> lastStateStates = new HashSet<LifecycleStateEnum>(); + Either<Map<String, List<? extends Component>>, ResponseFormat> response; + lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + lifecycleStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION); + lifecycleStates.add(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS); + lifecycleStates.add(LifecycleStateEnum.CERTIFIED); + // more states + lastStateStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION); + response = getFollowedProducts(userId, lifecycleStates, lastStateStates); + return response; + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleOps(String userId) { + Set<DistributionStatusEnum> distStatus = new HashSet<DistributionStatusEnum>(); + distStatus.add(DistributionStatusEnum.DISTRIBUTION_APPROVED); + distStatus.add(DistributionStatusEnum.DISTRIBUTED); + + Either<Map<String, List<? extends Component>>, ResponseFormat> result = handleFollowedCertifiedServices(distStatus); + return result; + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleFollowedCertifiedServices(Set<DistributionStatusEnum> distStatus) { + Map<String, Object> propertiesToMatch = new HashMap<>(); + propertiesToMatch.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.CERTIFIED.name()); + + Either<Set<Service>, StorageOperationStatus> services = serviceOperation.getCertifiedServicesWithDistStatus(propertiesToMatch, distStatus, false); + if (services.isLeft()) { + Map<String, List<? extends Component>> result = new HashMap<String, List<? extends Component>>(); + List<Service> list = new ArrayList<>(); + list.addAll(services.left().value()); + result.put("services", list); + return Either.left(result); + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value()))); + } + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> handleTester(String userId) { + Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>(); + lifecycleStates.add(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS); + Either<List<Resource>, StorageOperationStatus> resources = resourceOperation.getTesterFollowed(userId, lifecycleStates, false); + + if (resources.isLeft()) { + Either<List<Service>, StorageOperationStatus> services = serviceOperation.getTesterFollowed(userId, lifecycleStates, false); + if (services.isLeft()) { + Map<String, List<? extends Component>> result = new HashMap<String, List<? extends Component>>(); + result.put("services", services.left().value()); + result.put("resources", resources.left().value()); + return Either.left(result); + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value()))); + } + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value()))); + } + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) { + Either<List<Resource>, StorageOperationStatus> resources = resourceOperation.getFollowed(userId, lifecycleStates, lastStateStates, false); + + if (resources.isLeft()) { + Either<List<Service>, StorageOperationStatus> services = serviceOperation.getFollowed(userId, lifecycleStates, lastStateStates, false); + if (services.isLeft()) { + Map<String, List<? extends Component>> result = new HashMap<String, List<? extends Component>>(); + result.put("services", services.left().value()); + result.put("resources", resources.left().value()); + return Either.left(result); + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value()))); + } + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value()))); + } + } + + private Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) { + Either<List<Product>, StorageOperationStatus> products = productOperation.getFollowed(userId, lifecycleStates, lastStateStates, false); + if (products.isLeft()) { + Map<String, List<? extends Component>> result = new HashMap<String, List<? extends Component>>(); + result.put("products", products.left().value()); + return Either.left(result); + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value()))); + } + } + + /* + * New categories flow - start + */ + public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() { + return elementOperation.getAllResourceCategories(); + } + + public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() { + return elementOperation.getAllServiceCategories(); + } + + public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) { + + AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY; + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName); + String componentType = (componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue()); + CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY; + + User user = new User(); + Either<User, ResponseFormat> validateUser = validateUser(userId); + if (validateUser.isRight()) { + log.debug("Validation of user failed, userId {}", userId); + ResponseFormat responseFormat = validateUser.right().value(); + user = new User(); + user.setUserId(userId); + String currCategoryName = (category == null ? null : category.getName()); + handleCategoryAuditing(responseFormat, user, currCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + user = validateUser.left().value(); + + if (category == null) { + log.debug("Category json is invalid"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType); + return Either.right(responseFormat); + } + + String categoryName = category.getName(); + // For auditing of failures we need the original non-normalized name + String origCategoryName = categoryName; + if (componentTypeEnum == null) { + log.debug("Component type {} is invalid", componentTypeParamName); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum); + if (validateUserRole.isRight()) { + log.debug("Validation of user role failed, userId {}", userId); + ResponseFormat responseFormat = validateUserRole.right().value(); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) { + log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue()); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName); + + if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) { + log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + category.setName(categoryName); + + String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName); + category.setNormalizedName(normalizedName); + + NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType); + + Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName); + if (categoryUniqueEither.isRight()) { + log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value()); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Boolean isCategoryUnique = categoryUniqueEither.left().value(); + if (!isCategoryUnique) { + log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType); + if (createCategoryByType.isRight()) { + log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName); + handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); + return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value())); + } + category = createCategoryByType.left().value(); + log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType); + return Either.left(category); + } + + public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName, String parentCategoryId, String userId) { + + AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY; + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName); + String componentType = (componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue()); + CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY; + // For auditing + String parentCategoryName = parentCategoryId; + + if (subCategory == null) { + log.debug("Sub-category json is invalid"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType); + return Either.right(responseFormat); + } + + String subCategoryName = subCategory.getName(); + // For auditing of failures we need the original non-normalized name + String origSubCategoryName = subCategoryName; + + User user = new User(); + /* + * if (userId == null) { user.setUserId("UNKNOWN"); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, + * auditingAction, componentType); return Either.right(responseFormat); } + */ + Either<User, ResponseFormat> validateUser = validateUserExists(userId, "createSubCategory", false); + if (validateUser.isRight()) { + log.debug("Validation of user failed, userId {}", userId); + ResponseFormat responseFormat = validateUser.right().value(); + user = new User(); + user.setUserId(userId); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + user = validateUser.left().value(); + + if (componentTypeEnum == null) { + log.debug("Component type {} is invalid", componentTypeParamName); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType); + if (validateComponentType.isRight()) { + log.debug("Validation of component type for sub-category failed"); + ResponseFormat responseFormat = validateComponentType.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum); + if (validateUserRole.isRight()) { + log.debug("Validation of user role failed, userId {}", userId); + ResponseFormat responseFormat = validateUserRole.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY); + NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY); + + CategoryDefinition categoryDefinition; + Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId, componentTypeEnum); + if (validateCategoryExists.isRight()) { + log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId); + ResponseFormat responseFormat = validateCategoryExists.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + categoryDefinition = validateCategoryExists.left().value(); + parentCategoryName = categoryDefinition.getName(); + + if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) { + log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName); + + if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) { + log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName); + subCategory.setNormalizedName(normalizedName); + + // Uniqueness under this category + Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation.isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId); + if (subCategoryUniqueForCategory.isRight()) { + log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, normalizedName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Boolean isSubUnique = subCategoryUniqueForCategory.left().value(); + if (!isSubUnique) { + log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, normalizedName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + // Setting name of subcategory to fit the similar subcategory name + // ignoring cases. + // For example if Network-->kUKU exists for service category Network, + // and user is trying to create Router-->Kuku for service category + // Router, + // his subcategory name will be Router-->kUKU. + Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation.getSubCategoryUniqueForType(childNodeType, normalizedName); + if (subCategoryUniqueForType.isRight()) { + log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value(); + if (subCategoryDefinition != null) { + subCategoryName = subCategoryDefinition.getName(); + } + + subCategory.setName(subCategoryName); + ///////////////////////////////////////////// Validations end + + Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation.createSubCategory(parentCategoryId, subCategory, childNodeType); + if (createSubCategory.isRight()) { + log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); + return Either.right(responseFormat); + } + + SubCategoryDefinition subCategoryCreated = createSubCategory.left().value(); + log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType); + return Either.left(subCategoryCreated); + } + + public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName, String grandParentCategoryId, String parentSubCategoryId, String userId) { + + AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING; + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName); + String componentType = (componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue()); + CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING; + // For auditing + String parentCategoryName = grandParentCategoryId; + String parentSubCategoryName = parentSubCategoryId; + + User user; + Either<User, ResponseFormat> validateUser = validateUserExists(userId, "create Grouping", false); + if (validateUser.isRight()) { + log.debug("Validation of user failed, userId {}", userId); + ResponseFormat responseFormat = validateUser.right().value(); + user = new User(); + user.setUserId(userId); + String groupingNameForAudit = (grouping == null ? null : grouping.getName()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit, auditingAction, componentType); + return Either.right(responseFormat); + } + + user = validateUser.left().value(); + + if (grouping == null) { + log.debug("Grouping json is invalid"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType); + return Either.right(responseFormat); + } + + String groupingName = grouping.getName(); + // For auditing of failures we need the original non-normalized name + String origGroupingName = groupingName; + + if (componentTypeEnum == null) { + log.debug("Component type {} is invalid", componentTypeParamName); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType); + if (validateComponentType.isRight()) { + log.debug("Validation of component type for grouping failed"); + ResponseFormat responseFormat = validateComponentType.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum); + if (validateUserRole.isRight()) { + log.debug("Validation of user role failed, userId {}", userId); + ResponseFormat responseFormat = validateUserRole.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY); + NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY); + NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING); + + // Validate category + CategoryDefinition categoryDefinition; + Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId, componentTypeEnum); + if (validateCategoryExists.isRight()) { + log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId); + ResponseFormat responseFormat = validateCategoryExists.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + categoryDefinition = validateCategoryExists.left().value(); + parentCategoryName = categoryDefinition.getName(); + + // Validate subcategory + SubCategoryDefinition subCategoryDefinition; + Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId, componentTypeEnum); + if (validateSubCategoryExists.isRight()) { + log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId); + ResponseFormat responseFormat = validateSubCategoryExists.right().value(); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + subCategoryDefinition = validateSubCategoryExists.left().value(); + parentSubCategoryName = subCategoryDefinition.getName(); + + if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) { + log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName); + + if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) { + log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName); + grouping.setNormalizedName(normalizedName); + + // Uniqueness under this category + Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation.isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId); + if (groupingUniqueForSubCategory.isRight()) { + log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, normalizedName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value(); + if (!isGroupingUnique) { + log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, normalizedName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + // Setting name of grouping to fit the similar grouping name ignoring + // cases. + // For example if Network-->kUKU exists for service sub-category + // Network, and user is trying to create grouping Router-->Kuku for + // service sub-category Router, + // his grouping name will be Router-->kUKU. + Either<GroupingDefinition, ActionStatus> groupingUniqueForType = elementOperation.getGroupingUniqueForType(childNodeType, normalizedName); + if (groupingUniqueForType.isRight()) { + log.debug("Failed validation of whether similar grouping exists, normalizedName {} componentType {}", normalizedName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForType.right().value()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + GroupingDefinition groupingDefinition = groupingUniqueForType.left().value(); + if (groupingDefinition != null) { + groupingName = groupingDefinition.getName(); + } + + grouping.setName(groupingName); + ///////////////////////////////////////////// Validations end + + Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType); + if (createGrouping.isRight()) { + log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value()); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); + return Either.right(responseFormat); + } + + GroupingDefinition groupingCreated = createGrouping.left().value(); + log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction, componentType); + return Either.left(groupingCreated); + } + + public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) { + AuditingActionEnum auditingAction = AuditingActionEnum.GET_CATEGORY_HIERARCHY; + ResponseFormat responseFormat; + User user = new User(); + if (userId == null) { + user.setUserId("UNKNOWN"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat); + return Either.right(responseFormat); + } + + Either<User, ResponseFormat> validateUser = validateUserExists(userId, "get All Categories", false); + if (validateUser.isRight()) { + user.setUserId(userId); + log.debug("Validation of user failed, userId {}", userId); + responseFormat = validateUser.right().value(); + componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat); + return Either.right(responseFormat); + } + user = validateUser.left().value(); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + if (componentTypeEnum == null) { + log.debug("Cannot create category for component type {}", componentType); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type"); + componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat); + return Either.right(responseFormat); + } + + NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY); + Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false); + if (getAllCategoriesByType.isRight()) { + responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value()); + componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat); + return Either.right(responseFormat); + } + List<CategoryDefinition> categories = getAllCategoriesByType.left().value(); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat); + return Either.left(categories); + } + + public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Category", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName); + if (componentTypeEnum == null) { + log.debug("Cannot create category for component type {}", componentTypeParamName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY); + + Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId); + if (deleteCategoryByType.isRight()) { + // auditing, logging here... + return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value())); + } + CategoryDefinition category = deleteCategoryByType.left().value(); + log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId()); + return Either.left(category); + } + + public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String grandParentCategoryId, String parentSubCategoryId, String componentTypeParamName, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Sub Category", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName); + if (componentTypeEnum == null) { + log.debug("Cannot delete sub-category for component type {}", componentTypeParamName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY); + + Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId); + if (deleteSubCategoryByType.isRight()) { + // auditing, logging here... + return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value())); + } + SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value(); + log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId()); + return Either.left(subCategory); + } + + public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String grandParentCategoryId, String parentSubCategoryId, String groupingId, String componentTypeParamName, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Grouping", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName); + if (componentTypeEnum == null) { + log.debug("Cannot delete grouping for component type {}", componentTypeParamName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING); + + Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId); + if (deleteGroupingByType.isRight()) { + // auditing, logging here... + return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value())); + } + GroupingDefinition deletedGrouping = deleteGroupingByType.left().value(); + log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId()); + return Either.left(deletedGrouping); + } + + private Either<User, ResponseFormat> validateUser(String userId) { + + // validate user exists + if (userId == null) { + log.debug("User id is null"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION)); + } + + Either<User, ActionStatus> userResult = userAdminManager.getUser(userId, false); + if (userResult.isRight()) { + ResponseFormat responseFormat; + if (userResult.right().value().equals(ActionStatus.USER_NOT_FOUND)) { + log.debug("Not authorized user, userId = {}", userId); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + } else { + log.debug("Failed to authorize user, userId = {}", userId); + responseFormat = componentsUtils.getResponseFormat(userResult.right().value()); + } + + return Either.right(responseFormat); + } + return Either.left(userResult.left().value()); + // ========================================- + } + + private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) { + String role = user.getRole(); + boolean validAdminAction = (role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE)); + boolean validProductAction = (role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT)); + + if (!(validAdminAction || validProductAction)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role, componentTypeEnum); + return Either.right(responseFormat); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) { + boolean validResourceAction = (componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY || categoryType == CategoryTypeEnum.SUBCATEGORY)); + boolean validServiceAction = (componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY); + boolean validProductAction = (componentType == ComponentTypeEnum.PRODUCT); // can + // be + // any + // category + // type + + if (!(validResourceAction || validServiceAction || validProductAction)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType); + return Either.right(responseFormat); + } + return Either.left(true); + } + + private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId, ComponentTypeEnum componentType) { + Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId); + if (categoryByTypeAndId.isRight()) { + log.debug("Failed to fetch parent category, parent categoryId {}", categoryId); + ActionStatus actionStatus = categoryByTypeAndId.right().value(); + ResponseFormat responseFormat; + if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) { + responseFormat = componentsUtils.getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), ""); + } else { + responseFormat = componentsUtils.getResponseFormat(actionStatus); + } + return Either.right(responseFormat); + } + return Either.left(categoryByTypeAndId.left().value()); + } + + private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId, ComponentTypeEnum componentType) { + Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId); + if (subCategoryByTypeAndId.isRight()) { + log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId); + ActionStatus actionStatus = subCategoryByTypeAndId.right().value(); + ResponseFormat responseFormat; + if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) { + responseFormat = componentsUtils.getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), ""); + } else { + responseFormat = componentsUtils.getResponseFormat(actionStatus); + } + return Either.right(responseFormat); + } + return Either.left(subCategoryByTypeAndId.left().value()); + } + + private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction, String componentType) { + componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType); + } + + private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, AuditingActionEnum auditingAction, String componentType) { + componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType); + } + + private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping, AuditingActionEnum auditingAction, String componentType) { + componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType); + } + + /* + * New categories flow - end + */ + + public Either<List<Tag>, ActionStatus> getAllTags(String userId) { + Either<User, ActionStatus> resp = validateUserExistsActionStatus(userId, "get All Tags"); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + return elementOperation.getAllTags(); + } + + public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) { + Either<User, ActionStatus> resp = validateUserExistsActionStatus(userId, "get All Property Scopes"); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + return elementOperation.getAllPropertyScopes(); + } + + public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(String userId) { + Either<User, ActionStatus> resp = validateUserExistsActionStatus(userId, "get All Artifact Types"); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + return elementOperation.getAllArtifactTypes(); + } + + public Either<Map<String, Object>, ActionStatus> getAllDeploymentArtifactTypes() { + return elementOperation.getAllDeploymentArtifactTypes(); + } + + public Either<Integer, ActionStatus> getDefaultHeatTimeout() { + return elementOperation.getDefaultHeatTimeout(); + } + + public Either<Map<String, List<? extends Component>>, ResponseFormat> getCatalogComponents(String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Catalog Components", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Map<String, List<? extends Component>> resMap = new HashMap<>(); + + Either<List<Resource>, StorageOperationStatus> resResources = resourceOperation.getResourceCatalogData(false); + if (resResources.isLeft()) { + Either<List<Service>, StorageOperationStatus> resServices = serviceOperation.getServiceCatalogData(false); + if (resServices.isLeft()) { + Either<List<Product>, StorageOperationStatus> resProducts = productOperation.getProductCatalogData(false); + if (resProducts.isLeft()) { + resMap.put("resources", resResources.left().value()); + resMap.put("services", resServices.left().value()); + resMap.put("products", resProducts.left().value()); + return Either.left(resMap); + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resProducts.right().value()))); + } + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resServices.right().value()))); + } + } else { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resResources.right().value()))); + } + } + + public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, String query) { + ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType); + + if (query != null) { + Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum); + if (invalidFilter.isPresent()) { + log.debug("getFilteredAssetList: invalid filter key"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(), FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString())); + } + } + + if (filters == null || filters.isEmpty()) { + return getCatalogComponentsByAssetType(assetTypeEnum); + } + + ComponentOperation componentOperation = getComponentOperation(assetTypeEnum); + Either<List<Component>, StorageOperationStatus> result = componentOperation.getFilteredComponents(filters, false); + + if (result.isRight()) {// category hierarchy mismatch or + // category/subCategory/distributionStatus not + // found + List<String> params = getErrorResponseParams(filters, assetTypeEnum); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2))); + } + if (result.left().value().isEmpty()) {// no assets found for requested + // criteria + return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query)); + } + return Either.left(result.left().value()); + } + + public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByAssetType(ComponentTypeEnum assetTypeEnum) { + + if (assetTypeEnum == null) { + log.debug("getCatalogComponentsByAssetType: Corresponding ComponentTypeEnum not found"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + switch (assetTypeEnum) { + case RESOURCE: + + Either<List<Resource>, StorageOperationStatus> resourceCatalogData = resourceOperation.getResourceCatalogDataVFLatestCertifiedAndNonCertified(false); + if (resourceCatalogData.isLeft()) { + log.debug("getCatalogComponentsByAssetType: Resource fetching successful"); + return Either.left(resourceCatalogData.left().value()); + } else { + log.debug("getCatalogComponentsByAssetType: Resource fetching failed"); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resourceCatalogData.right().value()))); + } + + case SERVICE: + Either<List<Service>, StorageOperationStatus> serviceCatalogData = serviceOperation.getServiceCatalogDataLatestCertifiedAndNotCertified(false); + if (serviceCatalogData.isLeft()) { + log.debug("getCatalogComponentsByAssetType: Service fetching successful"); + return Either.left(serviceCatalogData.left().value()); + } else { + log.debug("getCatalogComponentsByAssetType: Service fetching failed"); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(serviceCatalogData.right().value()))); + } + /* + * case PRODUCT: Either<List<Product>, StorageOperationStatus> resCatalogData = productOperation.getProductCatalogData(false); if(resCatalogData.isLeft()){ log. debug("getCatalogComponentsByAssetType: Product fetching successful" ); + * return Either.left(resCatalogData.left().value()); }else { log. debug("getCatalogComponentsByAssetType: Product fetching failed" ); return Either.right(componentsUtils .getResponseFormat(componentsUtils.convertFromStorageResponse( + * resCatalogData.right().value()))); } + */ + default: + log.debug("Invalid Asset Type"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + } + + // TODO new story Tal + public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) { + + if (assetType == null || assetType == null) { + log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType); + + if (assetTypeEnum == null) { + log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + switch (assetTypeEnum) { + + case RESOURCE: + Either<List<Resource>, StorageOperationStatus> resourceListByUuid = resourceOperation.getLatestResourceByUuid(uuid, false); + + if (resourceListByUuid.isLeft()) { + log.debug("getCatalogComponentsByUuidAndAssetType: Resource fetching successful"); + return Either.left(resourceListByUuid.left().value()); + } + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(resourceListByUuid.right().value()); + log.debug("getCatalogComponentsByUuidAndAssetType: Resource fetching failed"); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + + case SERVICE: + Either<List<Service>, StorageOperationStatus> serviceCatalogData = serviceOperation.getLatestServiceByUuid(uuid, false); + + if (serviceCatalogData.isLeft()) { + log.debug("getCatalogComponentsByUuidAndAssetType: Service fetching successful"); + return Either.left(serviceCatalogData.left().value()); + } + + log.debug("getCatalogComponentsByUuidAndAssetType: Service fetching failed"); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(serviceCatalogData.right().value()))); + // case Product is for future US + /* + * case PRODUCT: Either<List<Product>, StorageOperationStatus> resCatalogData = productOperation.getProductCatalogData(false); if(resCatalogData.isLeft()){ log. debug("getCatalogComponentsByAssetType: Product fetching successful" ); return + * Either.left(resCatalogData.left().value()); }else { log. debug("getCatalogComponentsByAssetType: Product fetching failed" ); return Either.right(componentsUtils .getResponseFormat(componentsUtils.convertFromStorageResponse( + * resCatalogData.right().value()))); } + */ + default: + log.debug("Invalid Asset Type"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + } + + public List<String> getAllComponentTypesParamNames() { + List<String> paramNames = new ArrayList<>(); + paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME); + paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME); + paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME); + return paramNames; + } + + public List<String> getAllSupportedRoles() { + Role[] values = Role.values(); + List<String> roleNames = new ArrayList<>(); + for (Role role : values) { + roleNames.add(role.name()); + } + return roleNames; + } + + public Either<Map<String, String>, ActionStatus> getResourceTypesMap() { + return elementOperation.getResourceTypesMap(); + } + + private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) { + List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8); + List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType); + Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName()); + return params.stream().filter(noMatch).findAny(); + } + + private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) { + List<String> params = new ArrayList<String>(); + if (1 == filters.size()) { + params.add(assetType.getValue().toLowerCase()); + params.add(filters.keySet().iterator().next().getName()); + params.add(filters.values().iterator().next()); + } else { + params.add(assetType.getValue()); + params.add(filters.get(FilterKeyEnum.SUB_CATEGORY)); + params.add(filters.get(FilterKeyEnum.CATEGORY)); + } + return params; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java new file mode 100644 index 0000000000..3b4528d3a3 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java @@ -0,0 +1,1512 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.apache.commons.io.FilenameUtils; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.info.ArtifactDefinitionInfo; +import org.openecomp.sdc.be.info.ArtifactTemplateInfo; +import org.openecomp.sdc.be.info.GroupDefinitionInfo; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.GroupProperty; +import org.openecomp.sdc.be.model.GroupTypeDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.model.operations.impl.GroupOperation; +import org.openecomp.sdc.be.model.operations.impl.GroupTypeOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +@org.springframework.stereotype.Component("groupBusinessLogic") +public class GroupBusinessLogic extends BaseBusinessLogic { + + public static String INITIAL_VERSION = "1"; + + private static final String CREATE_GROUP = "CreateGroup"; + + private static final String UPDATE_GROUP = "UpdateGroup"; + + private static final String GET_GROUP = "GetGroup"; + + private static Logger log = LoggerFactory.getLogger(GroupBusinessLogic.class.getName()); + + public GroupBusinessLogic() { + + } + + @javax.annotation.Resource + private GroupTypeOperation groupTypeOperation; + + @javax.annotation.Resource + private GroupOperation groupOperation; + + /** + * + * 1. validate user exist + * + * 2. validate component can be edited + * + * 3. verify group not already exist + * + * 4. verify type of group exist + * + * 5. verify Component instances exist under the component + * + * 6. verify the component instances type are allowed according to the member types in the group type + * + * 7. verify the artifacts belongs to the component + * + * @param componentId + * @param userId + * @param componentType + * @param groupDefinition + * @param inTransaction + * @return + */ + public Either<GroupDefinition, ResponseFormat> createGroup(String componentId, String userId, ComponentTypeEnum componentType, GroupDefinition groupDefinition, boolean inTransaction) { + + Either<GroupDefinition, ResponseFormat> result = null; + + try { + Either<User, ResponseFormat> validateUserExists = validateUserExists(userId, CREATE_GROUP, inTransaction); + + if (validateUserExists.isRight()) { + result = Either.right(validateUserExists.right().value()); + return result; + } + + User user = validateUserExists.left().value(); + // 5. check service/resource existence + // 6. check service/resource check out + // 7. user is owner of checkout state + org.openecomp.sdc.be.model.Component component = null; + + // String realComponentId = componentType == + // ComponentTypeEnum.RESOURCE_INSTANCE ? parentId : componentId; + String realComponentId = componentId; + + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreArtifacts(false); + componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreComponentInstances(false); + + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(realComponentId, componentType, componentParametersView, userId, null, user); + + if (validateComponent.isRight()) { + result = Either.right(validateComponent.right().value()); + return result; + } + component = validateComponent.left().value(); + Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId); + if (canWork.isRight()) { + result = Either.right(canWork.right().value()); + return result; + } + + result = this.createGroup(component, user, componentType, groupDefinition, inTransaction); + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + } + } + + private String getComponentTypeForResponse(org.openecomp.sdc.be.model.Component component) { + String componentTypeForResponse = "SERVICE"; + if (component instanceof Resource) { + componentTypeForResponse = ((Resource) component).getResourceType().name(); + } + return componentTypeForResponse; + } + + /** + * Verify that the artifact members belongs to the component + * + * @param component + * @param artifacts + * @return + */ + private Either<Boolean, ResponseFormat> verifyArtifactsBelongsToComponent(Component component, List<String> artifacts, String context) { + + if (artifacts == null || true == artifacts.isEmpty()) { + return Either.left(true); + } + + Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts(); + if (deploymentArtifacts == null || true == deploymentArtifacts.isEmpty()) { + BeEcompErrorManager.getInstance().logInvalidInputError(context, "No deployment artifact found under component " + component.getNormalizedName(), ErrorSeverity.INFO); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + List<String> currentArtifacts = deploymentArtifacts.values().stream().map(p -> p.getUniqueId()).collect(Collectors.toList()); + log.debug("The deployment artifacts of component {} are {}", component.getNormalizedName(), deploymentArtifacts); + if (false == currentArtifacts.containsAll(artifacts)) { + BeEcompErrorManager.getInstance().logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + return Either.left(true); + + } + + /** + * Verify that the artifact members belongs to the component + * + * @param component + * @param artifacts + * @return + */ + private Either<List<ArtifactDefinition>, ResponseFormat> getArtifactsBelongsToComponent(Component component, List<String> artifacts, String context) { + + /* + * if (artifacts == null || true == artifacts.isEmpty()) { return Either.left(true); } + */ + + Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts(); + if (deploymentArtifacts == null || true == deploymentArtifacts.isEmpty()) { + BeEcompErrorManager.getInstance().logInvalidInputError(context, "No deployment artifact found under component " + component.getNormalizedName(), ErrorSeverity.INFO); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + List<ArtifactDefinition> resultList = new ArrayList(); + + for (String artifactId : artifacts) { + Optional<ArtifactDefinition> groupArtifactOp = deploymentArtifacts.values().stream().filter(p -> p.getUniqueId().equals(artifactId)).findAny(); + + if (groupArtifactOp.isPresent()) { + ArtifactDefinition groupArtifact = groupArtifactOp.get(); + resultList.add(groupArtifact); + } else { + BeEcompErrorManager.getInstance().logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + + } + } + + return Either.left(resultList); + + } + + /** + * verify that the members are component instances of the component + * + * @param component + * @param componentType + * @param groupMembers + * @param memberToscaTypes + * @return + */ + private Either<Boolean, ResponseFormat> verifyComponentInstancesAreValidMembers(Component component, ComponentTypeEnum componentType, String groupName, String groupType, Map<String, String> groupMembers, List<String> memberToscaTypes) { + + if (groupMembers == null || true == groupMembers.isEmpty()) { + return Either.left(true); + } + + if (memberToscaTypes == null || true == memberToscaTypes.isEmpty()) { + return Either.left(true); + } + + List<ComponentInstance> componentInstances = component.getComponentInstances(); + if (componentInstances != null && false == componentInstances.isEmpty()) { + Map<String, ComponentInstance> compInstUidToCompInstMap = componentInstances.stream().collect(Collectors.toMap(p -> p.getUniqueId(), p -> p)); + + Set<String> allCompInstances = compInstUidToCompInstMap.keySet(); + + for (Entry<String, String> groupMember : groupMembers.entrySet()) { + String compName = groupMember.getKey(); + String compUid = groupMember.getValue(); + + if (false == allCompInstances.contains(compUid)) { + /* + * %1 - member name %2 - group name %3 - VF name %4 - component type [VF ] + */ + String componentTypeForResponse = getComponentTypeForResponse(component); + + BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Not all group members exists under the component", ErrorSeverity.INFO); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, compName, groupName, component.getNormalizedName(), componentTypeForResponse)); + } + } + + ComponentOperation componentOperation = getComponentOperationByParentComponentType(componentType); + if (componentOperation instanceof ResourceOperation) { + ResourceOperation resourceOperation = (ResourceOperation) componentOperation; + + for (Entry<String, String> groupMember : groupMembers.entrySet()) { + + String componentInstName = groupMember.getKey(); + String componentInstUid = groupMember.getValue(); + + ComponentInstance componentInstance = compInstUidToCompInstMap.get(componentInstUid); + String componentUid = componentInstance.getComponentUid(); + List<String> componentToscaNames = new ArrayList<>(); + TitanOperationStatus status = resourceOperation.fillResourceDerivedListFromGraph(componentUid, componentToscaNames); + if (status != TitanOperationStatus.OK) { + BeEcompErrorManager.getInstance().logInternalFlowError(CREATE_GROUP, "Cannot find tosca list of component id " + componentUid, ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + log.debug("The tosca names of component id {} are {}", componentUid, memberToscaTypes); + + boolean found = false; + for (String memberToscaType : memberToscaTypes) { + if (componentToscaNames.contains(memberToscaType)) { + found = true; + break; + } + } + if (found == false) { + BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, + "No tosca types from " + memberToscaTypes + " can be found in the tosca list " + componentToscaNames + " of component " + componentInstance.getNormalizedName(), ErrorSeverity.INFO); + /* + * # %1 - member name # %2 - group name # %3 - group type + */ + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_TOSCA_NAME_OF_COMPONENT_INSTANCE, componentInstName, groupName, groupType)); + } else { + log.debug("Component instance {} fits to one of the required tosca types", componentInstance.getNormalizedName()); + } + } + } else { + BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Cannot find tosca list since it is not supported for product", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + return Either.left(true); + } + + public ComponentOperation getComponentOperation(NodeTypeEnum componentType) { + + switch (componentType) { + case Service: + case ResourceInstance: + return serviceOperation; + case Resource: + return resourceOperation; + default: + return null; + } + } + + /** + * Update specific group version + * + * @param groupDefinition + * @param inTransaction + * @return + */ + public Either<GroupDefinition, StorageOperationStatus> updateGroupVersion(GroupDefinition groupDefinition, boolean inTransaction) { + Either<GroupDefinition, StorageOperationStatus> result = null; + List<String> groupIdsToUpdateVersion = new ArrayList<>(); + groupIdsToUpdateVersion.add(groupDefinition.getUniqueId()); + Either<List<GroupDefinition>, StorageOperationStatus> updateGroupVersion = updateGroupVersion(groupIdsToUpdateVersion, inTransaction); + if (updateGroupVersion.isLeft()) { + result = Either.left(updateGroupVersion.left().value().get(0)); + } else { + log.debug("Failed to update group version. Status is {} ", updateGroupVersion.right().value()); + result = Either.right(updateGroupVersion.right().value()); + } + return result; + } + + /** + * Update list of groups versions + * + * @param groupsUniqueId + * @param inTransaction + * @return + */ + public Either<List<GroupDefinition>, StorageOperationStatus> updateGroupVersion(List<String> groupsUniqueId, boolean inTransaction) { + + Either<List<GroupDefinition>, StorageOperationStatus> result = null; + + try { + + result = groupOperation.updateGroupVersion(groupsUniqueId, true); + + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + } + + } + + /** + * Update GroupDefinition metadata + * + * @param componentId + * @param user + * @param groupId + * @param componentType + * @param groupUpdate + * @param inTransaction + * @return + */ + public Either<GroupDefinition, ResponseFormat> updateGroupMetadata(String componentId, User user, String groupUniqueId, ComponentTypeEnum componentType, GroupDefinition groupUpdate, boolean inTransaction) { + + Either<GroupDefinition, ResponseFormat> result = null; + + // Validate user and validate group belongs to component + List<GroupDefinition> groups = new ArrayList<>(); + groups.add(groupUpdate); + Either<Component, ResponseFormat> validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, user.getUserId(), componentType, groups, inTransaction); + if (validateGroupsBeforeUpdate.isRight()) { + result = Either.right(validateGroupsBeforeUpdate.right().value()); + return result; + } + Component component = validateGroupsBeforeUpdate.left().value(); + + // Get the GroupDefinition object + Either<GroupDefinition, StorageOperationStatus> groupStatus = groupOperation.getGroup(groupUniqueId); + if (groupStatus.isRight()) { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(groupStatus.right().value(), ComponentTypeEnum.SERVICE), "")); + } + GroupDefinition currentGroup = groupStatus.left().value(); + + // Validate group type is vfModule + if (!currentGroup.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE)) { + log.error("Group update metadata: Group type is different then: {}", Constants.DEFAULT_GROUP_VF_MODULE); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_TYPE, groupUpdate.getType()); + return Either.right(responseFormat); + } + + Either<GroupDefinition, ResponseFormat> validationRsponse = validateAndUpdateGroupMetadata(currentGroup, groupUpdate); + if (validationRsponse.isRight()) { + log.info("Group update metadata: validations field."); + return validationRsponse; + } + GroupDefinition groupToUpdate = validationRsponse.left().value(); + + // lock resource + Either<Boolean, ResponseFormat> lockResult = lockComponent(componentId, component, "Update GroupDefinition Metadata"); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either<GroupDefinition, StorageOperationStatus> updateResponse = groupOperation.updateGroupName(groupUniqueId, groupUpdate.getName(), inTransaction); + if (updateResponse.isRight()) { + titanGenericDao.rollback(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Update GroupDefinition Metadata"); + BeEcompErrorManager.getInstance().logBeSystemError("Update GroupDefinition Metadata"); + log.debug("failed to update sevice {}", groupToUpdate.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + titanGenericDao.commit(); + return Either.left(updateResponse.left().value()); + } finally { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + } + + /** + * Validate and update GroupDefinition metadata + * + * @param user + * @param currentGroup + * @param groupUpdate + * @return + */ + private Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(GroupDefinition currentGroup, GroupDefinition groupUpdate) { + // Check if to update, and update GroupDefinition name. + Either<Boolean, ResponseFormat> response = validateAndUpdateGroupName(currentGroup, groupUpdate); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + // Do not allow to update GroupDefinition version directly. + String versionUpdated = groupUpdate.getVersion(); + String versionCurrent = currentGroup.getVersion(); + if (versionUpdated != null && !versionCurrent.equals(versionUpdated)) { + log.info("update Group: recived request to update version to {} the field is not updatable ignoring.", versionUpdated); + } + + return Either.left(currentGroup); + } + + /** + * Validate and update GroupDefinition name + * + * @param user + * @param currentGroup + * @param groupUpdate + * @return + */ + private Either<Boolean, ResponseFormat> validateAndUpdateGroupName(GroupDefinition currentGroup, GroupDefinition groupUpdate) { + String nameUpdated = groupUpdate.getName(); + String nameCurrent = currentGroup.getName(); + if (!nameCurrent.equals(nameUpdated)) { + Either<Boolean, ResponseFormat> validatNameResponse = validateGroupName(currentGroup.getName(), groupUpdate.getName()); + if (validatNameResponse.isRight()) { + ResponseFormat errorRespons = validatNameResponse.right().value(); + return Either.right(errorRespons); + } + currentGroup.setName(groupUpdate.getName()); + } + return Either.left(true); + } + + /** + * Validate that group name to update is valid (same as current group name except for middle part). For example: Current group name: MyResource..MyDesc..Module-1 Group to update: MyResource..MyDesc2..Module-1 Verify that only the second part + * MyDesc was changed. + * + * @param currentGroupName + * @param groupUpdateName + * @return + */ + private Either<Boolean, ResponseFormat> validateGroupName(String currentGroupName, String groupUpdateName) { + try { + // Check if the group name is in old format. + if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupUpdateName).matches()) { + log.error("Group name {} is in old format", groupUpdateName); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME, groupUpdateName)); + } + + // Check that name pats 1 and 3 did not changed (only the second + // part can be changed) + // But verify before that the current group format is the new one + if (!Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(currentGroupName).matches()) { + String[] split1 = currentGroupName.split("\\.\\."); + String currentResourceName = split1[0]; + String currentCounter = split1[2]; + + String[] split2 = groupUpdateName.split("\\.\\."); + String groupUpdateResourceName = split2[0]; + String groupUpdateCounter = split2[2]; + + if (!currentResourceName.equals(groupUpdateResourceName)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentResourceName)); + } + + if (!currentCounter.equals(groupUpdateCounter)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentCounter)); + } + } + + return Either.left(true); + } catch (Exception e) { + log.error("Error valiadting group name", e); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + } + + /** + * associate artifacts to a given group + * + * @param componentId + * @param userId + * @param componentType + * @param groups + * @param shouldLockComp + * @param inTransaction + * @return + */ + public Either<List<GroupDefinition>, ResponseFormat> associateArtifactsToGroup(String componentId, String userId, ComponentTypeEnum componentType, List<GroupDefinition> groups, boolean shouldLockComp, boolean inTransaction) { + + Either<List<GroupDefinition>, ResponseFormat> result = null; + + if (shouldLockComp == true && inTransaction == true) { + BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); + // Cannot lock component since we are in a middle of another + // transaction. + ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + return result; + } + + Component component = null; + try { + + if (groups == null || groups.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); + } + + Either<Component, ResponseFormat> validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); + if (validateGroupsBeforeUpdate.isRight()) { + result = Either.right(validateGroupsBeforeUpdate.right().value()); + return result; + } + + component = validateGroupsBeforeUpdate.left().value(); + + if (shouldLockComp) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, "Group - Associate Artifacts"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + List<GroupDefinition> updatedGroups = new ArrayList<>(); + + List<GroupDefinition> componentGroups = component.getGroups(); + + // per group, associate to it the artifacts + for (GroupDefinition groupDefinition : groups) { + + GroupDefinition componentGroup = componentGroups.stream().filter(p -> p.getUniqueId().equals(groupDefinition.getUniqueId())).findFirst().orElse(null); + if (componentGroup != null) { + List<String> componentArtifacts = componentGroup.getArtifacts(); + int artifactsSizeInGroup = componentArtifacts == null ? 0 : componentArtifacts.size(); + if (artifactsSizeInGroup > 0) { + List<String> artifactsToAssociate = groupDefinition.getArtifacts(); + + // if no artifcats sent + if (artifactsToAssociate == null || true == artifactsToAssociate.isEmpty()) { + continue; + } + + boolean isChanged = componentArtifacts.removeAll(artifactsToAssociate); + if (isChanged) {// I.e. At least one artifact is already + // associated to the group + log.debug("Some of the artifacts already associated to group {}", groupDefinition.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_ASSOCIATED, componentGroup.getName())); + } + } + } + + Either<GroupDefinition, StorageOperationStatus> associateArtifactsToGroup = groupOperation.associateArtifactsToGroup(groupDefinition.getUniqueId(), groupDefinition.getArtifacts(), true); + + if (associateArtifactsToGroup.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateArtifactsToGroup.right().value()); + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); + return result; + } + updatedGroups.add(associateArtifactsToGroup.left().value()); + + } + + result = Either.left(updatedGroups); + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + + } + } + + public Either<List<GroupDefinition>, ResponseFormat> associateMembersToGroup(String componentId, String userId, ComponentTypeEnum componentType, List<GroupDefinition> groups, boolean shouldLockComp, boolean inTransaction) { + + Either<List<GroupDefinition>, ResponseFormat> result = null; + + if (shouldLockComp == true && inTransaction == true) { + BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); + // Cannot lock component since we are in a middle of another + // transaction. + ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + return result; + } + + Component component = null; + try { + + if (groups == null || groups.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); + } + + Either<Component, ResponseFormat> validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); + if (validateGroupsBeforeUpdate.isRight()) { + result = Either.right(validateGroupsBeforeUpdate.right().value()); + return result; + } + + component = validateGroupsBeforeUpdate.left().value(); + + if (shouldLockComp) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, "Group - Associate Members"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + List<GroupDefinition> updatedGroups = new ArrayList<>(); + + // per group, associate to it the members + for (GroupDefinition groupDefinition : groups) { + + Either<GroupDefinition, StorageOperationStatus> associateMembersToGroup = groupOperation.associateMembersToGroup(groupDefinition.getUniqueId(), groupDefinition.getMembers(), true); + + if (associateMembersToGroup.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateMembersToGroup.right().value()); + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); + return result; + } else { + updatedGroups.add(associateMembersToGroup.left().value()); + } + + } + + result = Either.left(updatedGroups); + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + + } + } + + /** + * associate artifacts to a given group + * + * @param componentId + * @param userId + * @param componentType + * @param groups + * @param shouldLockComp + * @param inTransaction + * @return + */ + public Either<GroupDefinitionInfo, ResponseFormat> getGroupWithArtifactsById(ComponentTypeEnum componentType, String componentId, String groupId, String userId, boolean inTransaction) { + + Either<GroupDefinitionInfo, ResponseFormat> result = null; + + // Validate user exist + Either<User, ResponseFormat> validateUserExists = validateUserExists(userId, UPDATE_GROUP, true); + + if (validateUserExists.isRight()) { + result = Either.right(validateUserExists.right().value()); + return result; + } + + User user = validateUserExists.left().value(); + + // Validate component exist + org.openecomp.sdc.be.model.Component component = null; + String realComponentId = componentId; + + try { + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreArtifacts(false); + componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreComponentInstances(false); + + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(realComponentId, componentType, componentParametersView, userId, null, user); + if (validateComponent.isRight()) { + result = Either.right(validateComponent.right().value()); + return result; + } + component = validateComponent.left().value(); + + // validate we can work on component + /* + * Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent( component, userId); if (canWork.isRight()) { result = Either.right(canWork.right().value()); return result; } + */ + List<GroupDefinition> groups = component.getGroups(); + Optional<GroupDefinition> findAny = groups.stream().filter(p -> p.getUniqueId().equals(groupId)).findAny(); + if (findAny.isPresent()) { + GroupDefinition group = findAny.get(); + Boolean isBase = null;// Constants.IS_BASE; + List<GroupProperty> props = group.getProperties(); + if (props != null && !props.isEmpty()) { + Optional<GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny(); + if (isBasePropOp.isPresent()) { + GroupProperty propIsBase = isBasePropOp.get(); + isBase = Boolean.parseBoolean(propIsBase.getValue()); + + } else { + BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO); + // return + // Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + + } + } + + List<ArtifactDefinitionInfo> artifacts = new ArrayList(); + List<String> artifactsIds = group.getArtifacts(); + if (artifactsIds != null && !artifactsIds.isEmpty()) { + Either<List<ArtifactDefinition>, ResponseFormat> getArtifacts = getArtifactsBelongsToComponent(component, artifactsIds, GET_GROUP); + if (getArtifacts.isRight()) { + log.debug("Faild to find artifacts in group {} under component {}", groupId, component.getUniqueId()); + // result = Either.right(getArtifacts.right().value()); + // return result; + } else { + + List<ArtifactDefinition> artifactsFromComponent = getArtifacts.left().value(); + if (artifactsFromComponent != null && !artifactsFromComponent.isEmpty()) { + for (ArtifactDefinition artifactDefinition : artifactsFromComponent) { + ArtifactDefinitionInfo artifactDefinitionInfo = new ArtifactDefinitionInfo(artifactDefinition); + artifacts.add(artifactDefinitionInfo); + } + } + } + } + GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group); + resultInfo.setIsBase(isBase); + if (!artifacts.isEmpty()) + resultInfo.setArtifacts(artifacts); + + result = Either.left(resultInfo); + + return result; + + } else { + log.debug("Faild to find group {} under component {}", groupId, component.getUniqueId()); + BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "group " + groupId + " not found under component " + component.getUniqueId(), ErrorSeverity.INFO); + String componentTypeForResponse = getComponentTypeForResponse(component); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(), componentTypeForResponse)); + return result; + + } + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + } + + } + + /** + * @param componentId + * @param userId + * @param componentType + * @param groups + * @param inTransaction + * @return + */ + private Either<org.openecomp.sdc.be.model.Component, ResponseFormat> validateGroupsBeforeUpdate(String componentId, String userId, ComponentTypeEnum componentType, List<GroupDefinition> groups, boolean inTransaction) { + + Either<org.openecomp.sdc.be.model.Component, ResponseFormat> result; + + // Validate user exist + Either<User, ResponseFormat> validateUserExists = validateUserExists(userId, UPDATE_GROUP, inTransaction); + if (validateUserExists.isRight()) { + result = Either.right(validateUserExists.right().value()); + return result; + } + User user = validateUserExists.left().value(); + + // Validate component exist + String realComponentId = componentId; + + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreArtifacts(false); + componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreComponentInstances(false); + + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(realComponentId, componentType, componentParametersView, userId, null, user); + + if (validateComponent.isRight()) { + result = Either.right(validateComponent.right().value()); + return result; + } + org.openecomp.sdc.be.model.Component component = validateComponent.left().value(); + + // validate we can work on component + Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId); + if (canWork.isRight()) { + result = Either.right(canWork.right().value()); + return result; + } + + // Validate groups exists in the component + ResponseFormat validateGroupsInComponent = validateGroupsInComponentByFunc(groups, component, p -> p.getUniqueId()); + if (validateGroupsInComponent != null) { + result = Either.right(validateGroupsInComponent); + return result; + } + + Set<String> artifacts = new HashSet<>(); + groups.forEach(p -> { + if (p.getArtifacts() != null) { + artifacts.addAll(p.getArtifacts()); + } + }); + // validate all artifacts belongs to the component + Either<Boolean, ResponseFormat> verifyArtifactsBelongsToComponent = verifyArtifactsBelongsToComponent(component, new ArrayList<>(artifacts), UPDATE_GROUP); + if (verifyArtifactsBelongsToComponent.isRight()) { + result = Either.right(verifyArtifactsBelongsToComponent.right().value()); + return result; + } + + return Either.left(component); + } + + private ResponseFormat validateGroupsInComponent(List<GroupDefinition> groups, org.openecomp.sdc.be.model.Component component) { + + Function<GroupDefinition, String> getByName = s -> s.getName(); + + return validateGroupsInComponentByFunc(groups, component, getByName); + + } + + /** + * @param groups + * @param component + * @param getByParam + * - the method to fetch the key of the GroupDefinition(from groups) in order to compare to groups in the component + * @return + */ + private ResponseFormat validateGroupsInComponentByFunc(List<GroupDefinition> groups, org.openecomp.sdc.be.model.Component component, Function<GroupDefinition, String> getByParam) { + ResponseFormat result = null; + + List<GroupDefinition> currentGroups = component.getGroups(); + + boolean found = false; + List<String> updatedGroupsName = groups.stream().map(getByParam).collect(Collectors.toList()); + + List<String> missingGroupNames = updatedGroupsName; + + if (currentGroups != null && false == currentGroups.isEmpty()) { + List<String> currentGroupsName = currentGroups.stream().map(getByParam).collect(Collectors.toList()); + + if (currentGroupsName.containsAll(updatedGroupsName)) { + found = true; + } else { + currentGroupsName.removeAll(currentGroupsName); + missingGroupNames = currentGroupsName; + } + } + if (false == found) { + String componentTypeForResponse = getComponentTypeForResponse(component); + String listOfGroups = getAsString(missingGroupNames); + result = componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, listOfGroups, component.getSystemName(), componentTypeForResponse); + return result; + } + + return null; + } + + public String getAsString(List<String> list) { + + if (list == null || list.isEmpty()) { + return ""; + } + StringBuilder builder = new StringBuilder(); + list.forEach(p -> builder.append(p + ",")); + + String result = builder.toString(); + return result.substring(0, result.length()); + + } + + /** + * dissociate artifacts from a given group + * + * @param componentId + * @param userId + * @param componentType + * @param groups + * @param shouldLockComp + * @param inTransaction + * @return + */ + public Either<List<GroupDefinition>, ResponseFormat> dissociateArtifactsFromGroup(String componentId, String userId, ComponentTypeEnum componentType, List<GroupDefinition> groups, boolean shouldLockComp, boolean inTransaction) { + + Either<List<GroupDefinition>, ResponseFormat> result = null; + + if (shouldLockComp == true && inTransaction == true) { + BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); + // Cannot lock component since we are in a middle of another + // transaction. + ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + return result; + } + + Component component = null; + + try { + + if (groups == null || groups.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); + } + + Either<Component, ResponseFormat> validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); + if (validateGroupsBeforeUpdate.isRight()) { + result = Either.right(validateGroupsBeforeUpdate.right().value()); + return result; + } + + component = validateGroupsBeforeUpdate.left().value(); + + if (shouldLockComp) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, "Group - Dissociate Artifacts"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + List<GroupDefinition> updatedGroups = new ArrayList<>(); + + List<GroupDefinition> componentGroups = component.getGroups(); + // per group, associate to it the artifacts + for (GroupDefinition groupDefinition : groups) { + + GroupDefinition componentGroup = componentGroups.stream().filter(p -> p.getUniqueId().equals(groupDefinition.getUniqueId())).findFirst().orElse(null); + if (componentGroup != null) { + List<String> componentArtifacts = componentGroup.getArtifacts(); + int artifactsSizeInGroup = componentArtifacts == null ? 0 : componentArtifacts.size(); + List<String> artifactsToDissociate = groupDefinition.getArtifacts(); + + // if no artifcats sent + if (artifactsToDissociate == null || true == artifactsToDissociate.isEmpty()) { + continue; + } + + if (artifactsSizeInGroup > 0) { + + boolean containsAll = componentArtifacts.containsAll(artifactsToDissociate); + if (false == containsAll) { // At least one artifact is + // not associated to the + // group + log.debug("Some of the artifacts already dissociated to group {}", groupDefinition.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_DISSOCIATED, componentGroup.getName())); + } + } else { + if (artifactsSizeInGroup == 0) { + if (artifactsToDissociate != null && false == artifactsToDissociate.isEmpty()) { + log.debug("No artifact is found under the group {}", groupDefinition.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_DISSOCIATED, componentGroup.getName())); + } + } + } + } + + Either<GroupDefinition, StorageOperationStatus> associateArtifactsToGroup = groupOperation.dissociateArtifactsFromGroup(groupDefinition.getUniqueId(), groupDefinition.getArtifacts(), true); + + if (associateArtifactsToGroup.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateArtifactsToGroup.right().value()); + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); + return result; + } + updatedGroups.add(associateArtifactsToGroup.left().value()); + + } + + result = Either.left(updatedGroups); + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + + } + + } + + public Either<List<GroupDefinition>, ResponseFormat> createGroups(String componentId, String userId, ComponentTypeEnum componentType, List<GroupDefinition> groupDefinitions, boolean shouldLockComp, boolean inTransaction) { + + Either<List<GroupDefinition>, ResponseFormat> result = null; + + List<GroupDefinition> groups = new ArrayList<>(); + org.openecomp.sdc.be.model.Component component = null; + try { + + if (groupDefinitions != null && false == groupDefinitions.isEmpty()) { + + if (shouldLockComp == true && inTransaction == true) { + BeEcompErrorManager.getInstance().logInternalFlowError("createGroups", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); + // Cannot lock component since we are in a middle of another + // transaction. + ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + return result; + } + + Either<User, ResponseFormat> validateUserExists = validateUserExists(userId, CREATE_GROUP, true); + if (validateUserExists.isRight()) { + result = Either.right(validateUserExists.right().value()); + return result; + } + + User user = validateUserExists.left().value(); + + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreArtifacts(false); + componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreComponentInstances(false); + + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView, userId, null, user); + + if (validateComponent.isRight()) { + result = Either.right(validateComponent.right().value()); + return result; + } + component = validateComponent.left().value(); + + if (shouldLockComp) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, "CreateGroups"); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId); + if (canWork.isRight()) { + result = Either.right(canWork.right().value()); + return result; + } + + for (GroupDefinition groupDefinition : groupDefinitions) { + Either<GroupDefinition, ResponseFormat> createGroup = this.createGroup(component, user, componentType, groupDefinition, true); + if (createGroup.isRight()) { + log.debug("Failed to create group {}.", groupDefinition); + result = Either.right(createGroup.right().value()); + return result; + } + GroupDefinition createdGroup = createGroup.left().value(); + groups.add(createdGroup); + } + } + + result = Either.left(groups); + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + + } + + } + + public Either<GroupDefinition, ResponseFormat> createGroup(Component component, User user, ComponentTypeEnum componentType, GroupDefinition groupDefinition, boolean inTransaction) { + + Either<GroupDefinition, ResponseFormat> result = null; + + log.debug("Going to create group {}", groupDefinition); + + try { + + // 3. verify group not already exist + List<GroupDefinition> groups = component.getGroups(); + boolean found = false; + if (groups != null && false == groups.isEmpty()) { + + GroupDefinition existGroupDef = groups.stream().filter(p -> p.getName().equalsIgnoreCase(groupDefinition.getName())).findFirst().orElse(null); + + found = existGroupDef != null; + } + + if (true == found) { + String componentTypeForResponse = getComponentTypeForResponse(component); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinition.getName(), component.getNormalizedName(), componentTypeForResponse)); + return result; + } + + // 4. verify type of group exist + String groupType = groupDefinition.getType(); + if (groupType == null || groupType.isEmpty()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupDefinition.getName())); + return result; + } + Either<GroupTypeDefinition, StorageOperationStatus> getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true); + if (getGroupType.isRight()) { + StorageOperationStatus status = getGroupType.right().value(); + if (status == StorageOperationStatus.NOT_FOUND) { + BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType)); + return result; + } else { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + } + + // 6. verify the component instances type are allowed according to + // the member types in the group type + GroupTypeDefinition groupTypeDefinition = getGroupType.left().value(); + + Either<Boolean, ResponseFormat> areValidMembers = verifyComponentInstancesAreValidMembers(component, componentType, groupDefinition.getName(), groupType, groupDefinition.getMembers(), groupTypeDefinition.getMembers()); + + if (areValidMembers.isRight()) { + ResponseFormat responseFormat = areValidMembers.right().value(); + result = Either.right(responseFormat); + return result; + } + + // 7. verify the artifacts belongs to the component + Either<Boolean, ResponseFormat> areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(), CREATE_GROUP); + if (areValidArtifacts.isRight()) { + ResponseFormat responseFormat = areValidArtifacts.right().value(); + result = Either.right(responseFormat); + return result; + } + + NodeTypeEnum nodeTypeEnum = componentType.getNodeType(); + + // add invariantUUID + String invariantUUID = UniqueIdBuilder.buildInvariantUUID(); + groupDefinition.setInvariantUUID(invariantUUID); + + // add groupUUID + String groupUUID = UniqueIdBuilder.generateUUID(); + groupDefinition.setGroupUUID(groupUUID); + + // add version + groupDefinition.setVersion(INITIAL_VERSION); + + // set groupType uid + groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId()); + + Either<GroupDefinition, StorageOperationStatus> addGroupToGraph = groupOperation.addGroup(nodeTypeEnum, component.getUniqueId(), groupDefinition, true); + + if (addGroupToGraph.isRight()) { + StorageOperationStatus storageOperationStatus = addGroupToGraph.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus); + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + log.debug("Failed to create group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); + } else { + GroupDefinition groupDefinitionCreated = addGroupToGraph.left().value(); + result = Either.left(groupDefinitionCreated); + } + + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + } + + } + + public Either<List<GroupDefinition>, ResponseFormat> updateVfModuleGroupNames(String resourceSystemName, List<GroupDefinition> groups, boolean inTransaction) { + List<GroupDefinition> updatedGroups = new ArrayList<>(); + Either<List<GroupDefinition>, ResponseFormat> updateGroupNamesRes = Either.left(updatedGroups); + Either<GroupDefinition, StorageOperationStatus> updateGroupNameRes; + Either<String, ResponseFormat> validateGenerateGroupNameRes; + int counter; + for (GroupDefinition group : groups) { + if (!group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches()) { + continue; + } + counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]); + validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), counter); + if (validateGenerateGroupNameRes.isRight()) { + updateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value()); + break; + } + updateGroupNameRes = groupOperation.updateGroupName(group.getUniqueId(), validateGenerateGroupNameRes.left().value(), inTransaction); + if (updateGroupNameRes.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(updateGroupNameRes.right().value()); + updateGroupNamesRes = Either.right(componentsUtils.getResponseFormat(actionStatus)); + break; + } + updatedGroups.add(updateGroupNameRes.left().value()); + } + return updateGroupNamesRes; + } + + public Either<Boolean, ResponseFormat> validateGenerateVfModuleGroupNames(List<ArtifactTemplateInfo> allGroups, String resourceSystemName, int startGroupCounter) { + Either<Boolean, ResponseFormat> validateGenerateGroupNamesRes = Either.left(true); + Collections.sort(allGroups, (art1, art2) -> ArtifactTemplateInfo.compareByGroupName(art1, art2)); + for (ArtifactTemplateInfo group : allGroups) { + Either<String, ResponseFormat> validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), startGroupCounter++); + if (validateGenerateGroupNameRes.isRight()) { + validateGenerateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value()); + break; + } + group.setGroupName(validateGenerateGroupNameRes.left().value()); + } + return validateGenerateGroupNamesRes; + } + + /** + * Generate module name from resourceName, description and counter + * + * @param resourceSystemName + * @param description + * @param groupCounter + * @return + */ + private Either<String, ResponseFormat> validateGenerateVfModuleGroupName(String resourceSystemName, String description, int groupCounter) { + Either<String, ResponseFormat> validateGenerateGroupNameRes; + if (resourceSystemName != null && description != null && Pattern.compile(Constants.MODULE_DESC_PATTERN).matcher(description).matches()) { + final String fileName = description.replaceAll("\\.\\.", "\\."); + validateGenerateGroupNameRes = Either.left(String.format(Constants.MODULE_NAME_FORMAT, resourceSystemName, FilenameUtils.removeExtension(fileName), groupCounter)); + } else { + validateGenerateGroupNameRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME)); + } + return validateGenerateGroupNameRes; + } + + public Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNames(Map<String, GroupDefinition> groups, String resourceSystemName) { + + Map<String, GroupDefinition> updatedNamesGroups = new HashMap<>(); + Either<Map<String, GroupDefinition>, ResponseFormat> result = Either.left(updatedNamesGroups); + for (Entry<String, GroupDefinition> groupEntry : groups.entrySet()) { + GroupDefinition curGroup = groupEntry.getValue(); + String groupType = curGroup.getType(); + String groupName = groupEntry.getKey(); + int counter; + String description; + Either<String, ResponseFormat> newGroupNameRes; + if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(groupName).matches()) { + + if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupEntry.getKey()).matches()) { + counter = Integer.parseInt(groupEntry.getKey().split(Constants.MODULE_NAME_DELIMITER)[1]); + description = curGroup.getDescription(); + } else { + counter = getNextVfModuleNameCounter(updatedNamesGroups); + description = groupName; + } + newGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, description, counter); + if (newGroupNameRes.isRight()) { + log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value()); + result = Either.right(newGroupNameRes.right().value()); + break; + } + groupName = newGroupNameRes.left().value(); + curGroup.setName(groupName); + } + updatedNamesGroups.put(groupName, curGroup); + } + return result; + } + + public int getNextVfModuleNameCounter(Map<String, GroupDefinition> groups) { + int counter = 0; + if (groups != null && !groups.isEmpty()) { + counter = getNextVfModuleNameCounter(groups.values()); + } + return counter; + } + + public int getNextVfModuleNameCounter(Collection<GroupDefinition> groups) { + int counter = 0; + if (groups != null && !groups.isEmpty()) { + List<Integer> counters = groups.stream().filter(group -> Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(group.getName()).matches() || Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches()) + .map(group -> Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1])).collect(Collectors.toList()); + counter = (counters == null || counters.isEmpty()) ? 0 : counters.stream().max((a, b) -> Integer.compare(a, b)).get() + 1; + } + return counter; + } + + public Either<List<GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesOnGraph(List<GroupDefinition> groups, String resourceSystemName, boolean inTransaction) { + List<GroupDefinition> updatedGroups = new ArrayList<>(); + Either<List<GroupDefinition>, ResponseFormat> result = Either.left(updatedGroups); + + for (GroupDefinition group : groups) { + String groupType = group.getType(); + String oldGroupName = group.getName(); + String newGroupName; + Either<String, ResponseFormat> newGroupNameRes; + Either<GroupDefinition, StorageOperationStatus> updateGroupNameRes; + int counter; + if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(oldGroupName).matches()) { + counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]); + newGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), counter); + if (newGroupNameRes.isRight()) { + log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value()); + result = Either.right(newGroupNameRes.right().value()); + break; + } + newGroupName = newGroupNameRes.left().value(); + updateGroupNameRes = groupOperation.updateGroupName(group.getUniqueId(), newGroupName, inTransaction); + if (updateGroupNameRes.isRight()) { + log.debug("Failed to update vf module group name for group {} . Status is {} ", oldGroupName, updateGroupNameRes.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupNameRes.right().value())); + result = Either.right(responseFormat); + break; + } + } + updatedGroups.add(group); + } + return result; + } + + public Either<List<GroupDefinition>, ResponseFormat> createGroups(Component component, User user, ComponentTypeEnum componentType, List<GroupDefinition> groupDefinitions, boolean inTransaction) { + + List<GroupDefinition> generatedGroups = new ArrayList<>(); + Either<List<GroupDefinition>, ResponseFormat> result = Either.left(generatedGroups); + + try { + + if (groupDefinitions != null && false == groupDefinitions.isEmpty()) { + for (GroupDefinition groupDefinition : groupDefinitions) { + Either<GroupDefinition, ResponseFormat> createGroup = this.createGroup(component, user, componentType, groupDefinition, true); + if (createGroup.isRight()) { + result = Either.right(createGroup.right().value()); + return result; + } + GroupDefinition generatedGroup = createGroup.left().value(); + generatedGroups.add(generatedGroup); + } + } + + return result; + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + } + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupTypeImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupTypeImportManager.java new file mode 100644 index 0000000000..3dee3839b1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupTypeImportManager.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.CommonImportManager.ElementTypeEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.GroupTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("groupTypeImportManager") +public class GroupTypeImportManager { + + public static void main(String[] args) { + + List<PropertyDefinition> properties = new ArrayList<>(); + PropertyDefinition propertyDefintion = new PropertyDefinition(); + propertyDefintion.setName("aaa"); + properties.add(propertyDefintion); + + List<String> allParentsProps = new ArrayList<>(); + allParentsProps.add("aaa"); + allParentsProps.add("bbb"); + + Set<String> alreadyExistPropsCollection = properties.stream().filter(p -> allParentsProps.contains(p.getName())).map(p -> p.getName()).collect(Collectors.toSet()); + System.out.println(alreadyExistPropsCollection); + + } + + private static Logger log = LoggerFactory.getLogger(GroupTypeImportManager.class.getName()); + @Resource + private PropertyOperation propertyOperation; + @Resource + private IGroupTypeOperation groupTypeOperation; + @Resource + private ComponentsUtils componentsUtils; + @Resource + private IResourceOperation resourceOperation; + + @Resource + private CommonImportManager commonImportManager; + + public Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat> createGroupTypes(String groupTypesYml) { + return commonImportManager.createElementTypes(groupTypesYml, elementTypeYml -> createGroupTypesFromYml(elementTypeYml), groupTypesList -> createGroupTypesByDao(groupTypesList), ElementTypeEnum.GroupType); + } + + private Either<List<GroupTypeDefinition>, ActionStatus> createGroupTypesFromYml(String groupTypesYml) { + + return commonImportManager.createElementTypesFromYml(groupTypesYml, (groupTypeName, groupTypeJsonData) -> createGroupType(groupTypeName, groupTypeJsonData)); + } + + private Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat> createGroupTypesByDao(List<GroupTypeDefinition> groupTypesToCreate) { + return commonImportManager.createElementTypesByDao(groupTypesToCreate, groupType -> validateGroupType(groupType), groupType -> new ImmutablePair<>(ElementTypeEnum.GroupType, groupType.getType()), + groupTypeName -> groupTypeOperation.getLatestGroupTypeByType(groupTypeName), groupType -> groupTypeOperation.addGroupType(groupType), null); + } + + private Either<ActionStatus, ResponseFormat> validateGroupType(GroupTypeDefinition groupType) { + Either<ActionStatus, ResponseFormat> result = Either.left(ActionStatus.OK); + if (groupType.getMembers() != null) { + if (groupType.getMembers().isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GROUP_MEMBER_EMPTY, groupType.getType()); + result = Either.right(responseFormat); + } else { + for (String member : groupType.getMembers()) { + // Verify that such Resource exist + Either<org.openecomp.sdc.be.model.Resource, StorageOperationStatus> eitherMemberExist = resourceOperation.getLatestByToscaResourceName(member, false); + if (eitherMemberExist.isRight()) { + StorageOperationStatus operationStatus = eitherMemberExist.right().value(); + log.debug("Error when fetching parent resource {}, error: {}", member, operationStatus); + ActionStatus convertFromStorageResponse = componentsUtils.convertFromStorageResponse(operationStatus); + BeEcompErrorManager.getInstance().logBeComponentMissingError("Import GroupType", "resource", member); + result = Either.right(componentsUtils.getResponseFormat(convertFromStorageResponse, member)); + break; + } + } + + } + } + return result; + } + + private GroupTypeDefinition createGroupType(String groupTypeName, Map<String, Object> toscaJson) { + + GroupTypeDefinition groupType = new GroupTypeDefinition(); + + if (toscaJson != null) { + // Description + final Consumer<String> descriptionSetter = description -> groupType.setDescription(description); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DESCRIPTION.getElementName(), descriptionSetter); + // Derived From + final Consumer<String> derivedFromSetter = derivedFrom -> groupType.setDerivedFrom(derivedFrom); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DERIVED_FROM.getElementName(), derivedFromSetter); + // Properties + commonImportManager.setProperties(toscaJson, (values) -> groupType.setProperties(values)); + // Metadata + final Consumer<Map<String, String>> metadataSetter = metadata -> groupType.setMetadata(metadata); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.METADATA.getElementName(), metadataSetter); + // Members + final Consumer<List<String>> membersSetter = members -> groupType.setMembers(members); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.MEMBERS.getElementName(), membersSetter); + + groupType.setType(groupTypeName); + + groupType.setHighestVersion(true); + + groupType.setVersion(ImportUtils.Constants.FIRST_CERTIFIED_VERSION_VERSION); + } + return groupType; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/HealthCheckBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/HealthCheckBusinessLogic.java new file mode 100644 index 0000000000..81dfc1a256 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/HealthCheckBusinessLogic.java @@ -0,0 +1,441 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import javax.servlet.ServletContext; + +import org.openecomp.sdc.be.components.distribution.engine.DistributionEngineClusterHealth; +import org.openecomp.sdc.be.components.distribution.engine.UebHealthCheckCall; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.IEsHealthCheckDao; +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.switchover.detector.SwitchoverDetector; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.api.HealthCheckInfo; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckComponent; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.WebApplicationContext; + +@Component("healthCheckBusinessLogic") +public class HealthCheckBusinessLogic { + + protected static String BE_HEALTH_LOG_CONTEXT = "be.healthcheck"; + + private static Logger healthLogger = LoggerFactory.getLogger(BE_HEALTH_LOG_CONTEXT); + + private static final String BE_HEALTH_CHECK_STR = "beHealthCheck"; + + @Resource + private TitanGenericDao titanGenericDao; + + @Resource + private IEsHealthCheckDao esHealthCheckDao; + + @Resource + private DistributionEngineClusterHealth distributionEngineClusterHealth; + + @Autowired + private SwitchoverDetector switchoverDetector; + + private static Logger log = LoggerFactory.getLogger(HealthCheckBusinessLogic.class.getName()); + + private volatile List<HealthCheckInfo> lastBeHealthCheckInfos = null; + + // private static volatile HealthCheckBusinessLogic instance; + // + public HealthCheckBusinessLogic() { + + } + + private ScheduledFuture<?> scheduledFuture = null; + + ScheduledExecutorService healthCheckScheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "BE-Health-Check-Task"); + } + }); + + HealthCheckScheduledTask healthCheckScheduledTask = null; + + @PostConstruct + public void init() { + + lastBeHealthCheckInfos = getBeHealthCheckInfos(); + + log.debug("After initializing lastBeHealthCheckInfos :{}", lastBeHealthCheckInfos); + + healthCheckScheduledTask = new HealthCheckScheduledTask(); + + if (this.scheduledFuture == null) { + this.scheduledFuture = this.healthCheckScheduler.scheduleAtFixedRate(healthCheckScheduledTask, 0, 3, TimeUnit.SECONDS); + } + + } + + // + // public static HealthCheckBusinessLogic getInstance(){ + //// if (instance == null){ + //// instance = init(); + //// } + // return instance; + // } + + // private synchronized static HealthCheckBusinessLogic init() { + // if (instance == null){ + // instance = new HealthCheckBusinessLogic(); + // } + // return instance; + // } + + private List<HealthCheckInfo> getBeHealthCheckInfos(ServletContext servletContext) { + + List<HealthCheckInfo> healthCheckInfos = new ArrayList<HealthCheckInfo>(); + + // BE + getBeHealthCheck(servletContext, healthCheckInfos); + + // ES + getEsHealthCheck(servletContext, healthCheckInfos); + + // Titan + getTitanHealthCheck(servletContext, healthCheckInfos); + + // Distribution Engine + getDistributionEngineCheck(servletContext, healthCheckInfos); + + return healthCheckInfos; + } + + private List<HealthCheckInfo> getBeHealthCheck(ServletContext servletContext, List<HealthCheckInfo> healthCheckInfos) { + String appVersion = ExternalConfiguration.getAppVersion(); + String description = "OK"; + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.BE, HealthCheckStatus.UP, appVersion, description)); + return healthCheckInfos; + } + + public List<HealthCheckInfo> getTitanHealthCheck(ServletContext servletContext, List<HealthCheckInfo> healthCheckInfos) { + // Titan health check and version + TitanGenericDao titanStatusDao = (TitanGenericDao) getDao(servletContext, TitanGenericDao.class); + String description; + boolean isTitanUp; + + try { + isTitanUp = titanStatusDao.isGraphOpen(); + } catch (Exception e) { + description = "Titan error: " + e.getMessage(); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.DOWN, null, description)); + return healthCheckInfos; + } + if (isTitanUp) { + description = "OK"; + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.UP, null, description)); + } else { + description = "Titan graph is down"; + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.DOWN, null, description)); + } + return healthCheckInfos; + } + + public List<HealthCheckInfo> getEsHealthCheck(ServletContext servletContext, List<HealthCheckInfo> healthCheckInfos) { + + // ES health check and version + IEsHealthCheckDao esStatusDao = (IEsHealthCheckDao) getDao(servletContext, IEsHealthCheckDao.class); + HealthCheckStatus healthCheckStatus; + String description; + + try { + healthCheckStatus = esStatusDao.getClusterHealthStatus(); + } catch (Exception e) { + healthCheckStatus = HealthCheckStatus.DOWN; + description = "ES cluster error: " + e.getMessage(); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, healthCheckStatus, null, description)); + return healthCheckInfos; + } + if (healthCheckStatus.equals(HealthCheckStatus.DOWN)) { + description = "ES cluster is down"; + } else { + description = "OK"; + } + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, healthCheckStatus, null, description)); + return healthCheckInfos; + } + + public Object getDao(ServletContext servletContext, Class<?> clazz) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) servletContext.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(servletContext); + + return webApplicationContext.getBean(clazz); + } + + private void getDistributionEngineCheck(ServletContext servletContext, List<HealthCheckInfo> healthCheckInfos) { + + DistributionEngineClusterHealth deDao = (DistributionEngineClusterHealth) getDao(servletContext, DistributionEngineClusterHealth.class); + HealthCheckInfo healthCheckInfo = deDao.getHealthCheckInfo(); + + healthCheckInfos.add(healthCheckInfo); + + } + + public boolean isDistributionEngineUp(ServletContext servletContext) { + + DistributionEngineClusterHealth deDao = (DistributionEngineClusterHealth) getDao(servletContext, DistributionEngineClusterHealth.class); + HealthCheckInfo healthCheckInfo = deDao.getHealthCheckInfo(); + if (healthCheckInfo.getHealthCheckStatus().equals(HealthCheckStatus.DOWN)) { + return false; + } + return true; + } + + public List<HealthCheckInfo> getBeHealthCheckInfosStatus() { + + return lastBeHealthCheckInfos; + + } + + private List<HealthCheckInfo> getBeHealthCheckInfos() { + + log.trace("In getBeHealthCheckInfos"); + + List<HealthCheckInfo> healthCheckInfos = new ArrayList<HealthCheckInfo>(); + + // BE + getBeHealthCheck(healthCheckInfos); + + // ES + getEsHealthCheck(healthCheckInfos); + + // Titan + getTitanHealthCheck(healthCheckInfos); + + // Distribution Engine + getDistributionEngineCheck(healthCheckInfos); + + return healthCheckInfos; + } + + private List<HealthCheckInfo> getBeHealthCheck(List<HealthCheckInfo> healthCheckInfos) { + String appVersion = ExternalConfiguration.getAppVersion(); + String description = "OK"; + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.BE, HealthCheckStatus.UP, appVersion, description)); + return healthCheckInfos; + } + + public List<HealthCheckInfo> getEsHealthCheck(List<HealthCheckInfo> healthCheckInfos) { + + // ES health check and version + HealthCheckStatus healthCheckStatus; + String description; + + try { + healthCheckStatus = esHealthCheckDao.getClusterHealthStatus(); + } catch (Exception e) { + healthCheckStatus = HealthCheckStatus.DOWN; + description = "ES cluster error: " + e.getMessage(); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, healthCheckStatus, null, description)); + return healthCheckInfos; + } + if (healthCheckStatus.equals(HealthCheckStatus.DOWN)) { + description = "ES cluster is down"; + } else { + description = "OK"; + } + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, healthCheckStatus, null, description)); + return healthCheckInfos; + } + + public List<HealthCheckInfo> getTitanHealthCheck(List<HealthCheckInfo> healthCheckInfos) { + // Titan health check and version + String description; + boolean isTitanUp; + + try { + isTitanUp = titanGenericDao.isGraphOpen(); + } catch (Exception e) { + description = "Titan error: " + e.getMessage(); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.DOWN, null, description)); + return healthCheckInfos; + } + if (isTitanUp) { + description = "OK"; + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.UP, null, description)); + } else { + description = "Titan graph is down"; + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.DOWN, null, description)); + } + return healthCheckInfos; + } + + private void getDistributionEngineCheck(List<HealthCheckInfo> healthCheckInfos) { + + HealthCheckInfo healthCheckInfo = distributionEngineClusterHealth.getHealthCheckInfo(); + + healthCheckInfos.add(healthCheckInfo); + + } + + @PreDestroy + private void destroy() { + + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + scheduledFuture = null; + } + + if (healthCheckScheduler != null) { + healthCheckScheduler.shutdown(); + } + + } + + public class HealthCheckScheduledTask implements Runnable { + + List<UebHealthCheckCall> healthCheckCalls = new ArrayList<>(); + + public HealthCheckScheduledTask() { + + } + + @Override + public void run() { + + healthLogger.trace("Executing BE Health Check Task"); + + List<HealthCheckInfo> beHealthCheckInfos = getBeHealthCheckInfos(); + boolean healthStatus = getAggregateBeStatus(beHealthCheckInfos); + + boolean lastHealthStatus = getAggregateBeStatus(lastBeHealthCheckInfos); + + if (lastHealthStatus != healthStatus) { + log.trace("BE Health State Changed to {}. Issuing alarm / recovery alarm...", healthStatus); + + lastBeHealthCheckInfos = beHealthCheckInfos; + logAlarm(healthStatus); + + } else { + // check if we need to update the status's list in case one of + // the statuses was changed + if (true == anyStatusChanged(beHealthCheckInfos, lastBeHealthCheckInfos)) { + lastBeHealthCheckInfos = beHealthCheckInfos; + } + + } + + } + + } + + private void logAlarm(boolean lastHealthState) { + if (lastHealthState == true) { + BeEcompErrorManager.getInstance().logBeHealthCheckRecovery(BE_HEALTH_CHECK_STR); + } else { + BeEcompErrorManager.getInstance().logBeHealthCheckError(BE_HEALTH_CHECK_STR); + } + } + + private boolean getAggregateBeStatus(List<HealthCheckInfo> beHealthCheckInfos) { + + boolean status = true; + + for (HealthCheckInfo healthCheckInfo : beHealthCheckInfos) { + if (healthCheckInfo.getHealthCheckStatus().equals(HealthCheckStatus.DOWN) && healthCheckInfo.getHealthCheckComponent() != HealthCheckComponent.DE) { + status = false; + break; + } + } + return status; + } + + public String getSiteMode() { + return switchoverDetector.getSiteMode(); + } + + public boolean anyStatusChanged(List<HealthCheckInfo> beHealthCheckInfos, List<HealthCheckInfo> lastBeHealthCheckInfos) { + + boolean result = false; + + if (beHealthCheckInfos != null && lastBeHealthCheckInfos != null) { + + Map<HealthCheckComponent, HealthCheckStatus> currentValues = beHealthCheckInfos.stream().collect(Collectors.toMap(p -> p.getHealthCheckComponent(), p -> p.getHealthCheckStatus())); + Map<HealthCheckComponent, HealthCheckStatus> lastValues = lastBeHealthCheckInfos.stream().collect(Collectors.toMap(p -> p.getHealthCheckComponent(), p -> p.getHealthCheckStatus())); + + if (currentValues != null && lastValues != null) { + int currentSize = currentValues.size(); + int lastSize = lastValues.size(); + + if (currentSize != lastSize) { + result = true; + } else { + + for (Entry<HealthCheckComponent, HealthCheckStatus> entry : currentValues.entrySet()) { + HealthCheckComponent key = entry.getKey(); + HealthCheckStatus value = entry.getValue(); + + if (false == lastValues.containsKey(key)) { + result = true; + break; + } + + HealthCheckStatus lastHealthCheckStatus = lastValues.get(key); + + if (value != lastHealthCheckStatus) { + result = true; + break; + } + } + } + } else if (currentValues == null && lastValues == null) { + result = false; + } else { + result = true; + } + + } else if (beHealthCheckInfos == null && lastBeHealthCheckInfos == null) { + result = false; + } else { + result = true; + } + + return result; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/IDeploymentArtifactTypeConfigGetter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/IDeploymentArtifactTypeConfigGetter.java new file mode 100644 index 0000000000..68569ebc3b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/IDeploymentArtifactTypeConfigGetter.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.config.Configuration.DeploymentArtifactTypeConfig; + +public interface IDeploymentArtifactTypeConfigGetter { + DeploymentArtifactTypeConfig getDeploymentArtifactConfig(); +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java new file mode 100644 index 0000000000..94a7340ff7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java @@ -0,0 +1,722 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.text.translate.CharSequenceTranslator; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.model.AttributeDefinition; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.heat.HeatParameterType; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.util.GsonFactory; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.representer.Representer; +import org.yaml.snakeyaml.resolver.Resolver; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import fj.data.Either; + +public final class ImportUtils { + private ImportUtils() { + + } + + private static CustomResolver customResolver = new CustomResolver(); + + private static class CustomResolver extends Resolver { + protected void addImplicitResolvers() { + // avoid implicit resolvers + } + } + + public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParamsWithoutImplicitTypes(String heatDecodedPayload, String artifactType) { + Map<String, Object> heatData = (Map<String, Object>) new Yaml(new Constructor(), new Representer(), new DumperOptions(), customResolver).load(heatDecodedPayload); + return getHeatParameters(heatData, artifactType); + } + + public static class Constants { + + public static final String FIRST_CERTIFIED_VERSION_VERSION = "1.0"; + public static final String FIRST_NON_CERTIFIED_VERSION = "0.1"; + public static final String VENDOR_NAME = "ATT (Tosca)"; + public static final String VENDOR_RELEASE = "1.0.0.wd03"; + public static final LifecycleStateEnum NORMATIVE_TYPE_LIFE_CYCLE = LifecycleStateEnum.CERTIFIED; + public static final boolean NORMATIVE_TYPE_HIGHEST_VERSION = true; + // public static final String ABSTRACT_CATEGORY = "Generic/Abstract"; + public static final String ABSTRACT_CATEGORY_NAME = "Generic"; + public static final String ABSTRACT_SUBCATEGORY = "Abstract"; + public static final String DEFAULT_ICON = "defaulticon"; + public static final String INNER_VFC_DESCRIPTION = "Not reusable inner VFC"; + public static final String USER_DEFINED_RESOURCE_NAMESPACE_PREFIX = "org.openecomp.resource."; + public static final List<String> TOSCA_DEFINITION_VERSIONS = Arrays.asList(new String[] { "tosca_simple_yaml_1_0_0", "tosca_simple_profile_for_nfv_1_0_0", "tosca_simple_yaml_1_0" }); + public static final List<String> TOSCA_YML_CSAR_VALID_SUFFIX = Arrays.asList(new String[] { ".yml", ".yaml", ".csar" }); + public static final String UI_JSON_PAYLOAD_NAME = "payloadName"; + public static final String ABSTRACT_NODE = "abstact"; + } + + public enum ResultStatusEnum { + ELEMENT_NOT_FOUND, GENERAL_ERROR, OK, INVALID_PROPERTY_DEFAULT_VALUE, INVALID_PROPERTY_TYPE, INVALID_PROPERTY_VALUE, MISSING_ENTRY_SCHEMA_TYPE + } + + public enum ToscaElementTypeEnum { + BOOLEAN, STRING, MAP, LIST, ALL + } + + public enum ToscaTagNamesEnum { + DERIVED_FROM("derived_from"), IS_PASSWORD("is_password"), + // Properties + PROPERTIES("properties"), TYPE("type"), STATUS("status"), ENTRY_SCHEMA("entry_schema"), REQUIRED("required"), DESCRIPTION("description"), DEFAULT_VALUE("default"), VALUE("value"), CONSTRAINTS("constraints"), + // Group Types + MEMBERS("members"), METADATA("metadata"), + // Policy Types + TARGETS("targets"), + // Capabilities + CAPABILITIES("capabilities"), VALID_SOURCE_TYPES("valid_source_types"), + // Requirements + REQUIREMENTS("requirements"), NODE("node"), RELATIONSHIP("relationship"), CAPABILITY("capability"), INTERFACES("interfaces"), + // Heat env Validation + PARAMETERS("parameters"), + // Import Validations + TOSCA_VERSION("tosca_definitions_version"), TOPOLOGY_TEMPLATE("topology_template"), NODE_TYPES("node_types"), OCCURRENCES("occurrences"), NODE_TEMPLATES("node_templates"), GROUPS("groups"), INPUTS("inputs"), + // Attributes + ATTRIBUTES("attributes"), LABEL("label"), HIDDEN("hidden"), IMMUTABLE("immutable"), GET_INPUT("get_input"); + + private String elementName; + + private ToscaTagNamesEnum(String elementName) { + this.elementName = elementName; + } + + public String getElementName() { + return elementName; + } + } + + @SuppressWarnings("unchecked") + private static void handleElementNameNotFound(String elementName, Object elementValue, ToscaElementTypeEnum elementType, List<Object> returnedList) { + if (elementValue instanceof Map) { + ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList); + } else if (elementValue instanceof List) { + ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList); + } + } + + @SuppressWarnings("unchecked") + private static void handleElementNameFound(String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList, Object elementValue) { + + if (elementValue instanceof Boolean) { + if (elementType == ToscaElementTypeEnum.BOOLEAN || elementType == ToscaElementTypeEnum.ALL) { + returnedList.add(elementValue); + } + } + + else if (elementValue instanceof String) { + if (elementType == ToscaElementTypeEnum.STRING || elementType == ToscaElementTypeEnum.ALL) { + returnedList.add(elementValue); + } + } else if (elementValue instanceof Map) { + if (elementType == ToscaElementTypeEnum.MAP || elementType == ToscaElementTypeEnum.ALL) { + returnedList.add(elementValue); + } + ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList); + + } else if (elementValue instanceof List) { + if (elementType == ToscaElementTypeEnum.LIST || elementType == ToscaElementTypeEnum.ALL) { + returnedList.add(elementValue); + } + ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList); + + } + // For Integer, Double etc... + else if (elementType == ToscaElementTypeEnum.ALL) { + if (elementValue != null) { + returnedList.add(String.valueOf(elementValue)); + } else { + returnedList.add(elementValue); + } + + } + } + + private static void findAllToscaElementsInList(List<Object> list, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) { + Iterator<Object> listItr = list.iterator(); + while (listItr.hasNext()) { + Object elementValue = listItr.next(); + handleElementNameNotFound(elementName, elementValue, elementType, returnedList); + } + + } + + public static Either<Object, ResultStatusEnum> findToscaElement(Map<String, Object> toscaJson, ToscaTagNamesEnum elementName, ToscaElementTypeEnum elementType) { + List<Object> foundElements = new ArrayList<>(); + Either<Object, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + ImportUtils.findToscaElements(toscaJson, elementName.getElementName(), elementType, foundElements); + if (foundElements.size() > 0) { + returnedElement = Either.left(foundElements.get(0)); + } + return returnedElement; + + } + + /** + * Recursively searches for all tosca elements with key equals to elementName and value equals to elementType. <br> + * Returns Either element with:<br> + * List with all value if values found<br> + * Or ELEMENT_NOT_FOUND ActionStatus + * + * @param toscaJson + * @param toscaTagName + * @return + */ + public static Either<List<Object>, ResultStatusEnum> findToscaElements(Map<String, Object> toscaJson, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) { + Either<List<Object>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + String skipKey = null; + if (toscaJson.containsKey(elementName)) { + Object elementValue = toscaJson.get(elementName); + handleElementNameFound(elementName, elementType, returnedList, elementValue); + skipKey = elementName; + } + + Iterator<Entry<String, Object>> keyValItr = toscaJson.entrySet().iterator(); + while (keyValItr.hasNext()) { + Entry<String, Object> keyValEntry = keyValItr.next(); + if (!String.valueOf(keyValEntry.getKey()).equals(skipKey)) { + handleElementNameNotFound(elementName, keyValEntry.getValue(), elementType, returnedList); + } + } + + if (returnedList.size() > 0) { + returnedElement = Either.left(returnedList); + } + + return returnedElement; + } + + @SuppressWarnings("unchecked") + public static <T> Either<List<T>, ResultStatusEnum> findFirstToscaListElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) { + Either<List<T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.LIST); + if (findFirstToscaElement.isLeft()) { + returnedElement = Either.left((List<T>) findFirstToscaElement.left().value()); + } + return returnedElement; + + } + + @SuppressWarnings("unchecked") + public static <T> Either<Map<String, T>, ResultStatusEnum> findFirstToscaMapElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) { + Either<Map<String, T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.MAP); + if (findFirstToscaElement.isLeft()) { + returnedElement = Either.left((Map<String, T>) findFirstToscaElement.left().value()); + } + return returnedElement; + + } + + public static Either<String, ResultStatusEnum> findFirstToscaStringElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) { + Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.STRING); + if (findFirstToscaElements.isLeft()) { + returnedElement = Either.left((String) findFirstToscaElements.left().value()); + } + return returnedElement; + } + + /** + * searches for first Tosca in Json map (toscaJson) boolean element by name (toscaTagName) returns found element or ELEMENT_NOT_FOUND status + * + * @param toscaJson + * @param toscaTagName + * @return + */ + public static Either<String, ResultStatusEnum> findFirstToscaBooleanElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) { + Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.BOOLEAN); + if (findFirstToscaElements.isLeft()) { + returnedElement = Either.left(String.valueOf(findFirstToscaElements.left().value())); + } + return returnedElement; + } + + private static void setPropertyConstraints(Map<String, Object> propertyValue, PropertyDefinition property) { + Either<List<Object>, ResultStatusEnum> propertyFieldconstraints = findFirstToscaListElement(propertyValue, ToscaTagNamesEnum.CONSTRAINTS); + if (propertyFieldconstraints.isLeft()) { + List<Object> jsonConstraintList = propertyFieldconstraints.left().value(); + + List<PropertyConstraint> constraintList = new ArrayList<>(); + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create(); + + for (Object constraintJson : jsonConstraintList) { + PropertyConstraint propertyConstraint = gson.fromJson(gson.toJson(constraintJson), constraintType); + constraintList.add(propertyConstraint); + } + property.setConstraints(constraintList); + } + } + + public static PropertyDefinition createModuleProperty(Map<String, Object> propertyValue) { + + PropertyDefinition propertyDef = new PropertyDefinition(); + ImportUtils.setField(propertyValue, ToscaTagNamesEnum.TYPE, type -> propertyDef.setType(type)); + ImportUtils.setPropertyFieldRequired(propertyValue, propertyDef); + ImportUtils.setField(propertyValue, ToscaTagNamesEnum.DESCRIPTION, desc -> propertyDef.setDescription(desc)); + + Either<Object, ResultStatusEnum> findToscaElement = ImportUtils.findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); + if (findToscaElement.isLeft()) { + String propertyJsonStringValue = getPropertyJsonStringValue(findToscaElement.left().value(), propertyDef.getType()); + propertyDef.setDefaultValue(propertyJsonStringValue); + } + ImportUtils.setField(propertyValue, ToscaTagNamesEnum.IS_PASSWORD, pass -> propertyDef.setPassword(Boolean.parseBoolean(pass))); + ImportUtils.setField(propertyValue, ToscaTagNamesEnum.STATUS, status -> propertyDef.setStatus(status)); + ImportUtils.setPropertyScheme(propertyValue, propertyDef); + ImportUtils.setPropertyConstraints(propertyValue, propertyDef); + + return propertyDef; + } + + public static InputDefinition createModuleInput(Map<String, Object> inputValue) { + + InputDefinition inputDef = new InputDefinition(); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.TYPE, type -> inputDef.setType(type)); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.REQUIRED, req -> inputDef.setRequired(Boolean.parseBoolean(req))); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.DESCRIPTION, desc -> inputDef.setDescription(desc)); + + Either<Object, ResultStatusEnum> findToscaElement = ImportUtils.findToscaElement(inputValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); + if (findToscaElement.isLeft()) { + String propertyJsonStringValue = getPropertyJsonStringValue(findToscaElement.left().value(), inputDef.getType()); + inputDef.setDefaultValue(propertyJsonStringValue); + } + ImportUtils.setField(inputValue, ToscaTagNamesEnum.IS_PASSWORD, pass -> inputDef.setPassword(Boolean.parseBoolean(pass))); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.STATUS, status -> inputDef.setStatus(status)); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.LABEL, label -> inputDef.setLabel(label)); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.HIDDEN, hidden -> inputDef.setHidden(Boolean.parseBoolean(hidden))); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.HIDDEN, immutable -> inputDef.setImmutable(Boolean.parseBoolean(immutable))); + ImportUtils.setField(inputValue, ToscaTagNamesEnum.LABEL, label -> inputDef.setLabel(label)); + ImportUtils.setPropertyScheme(inputValue, inputDef); + ImportUtils.setPropertyConstraints(inputValue, inputDef); + + return inputDef; + } + + public static AttributeDefinition createModuleAttribute(Map<String, Object> attributeMap) { + + AttributeDefinition attributeDef = new AttributeDefinition(); + ImportUtils.setField(attributeMap, ToscaTagNamesEnum.TYPE, type -> attributeDef.setType(type)); + ImportUtils.setField(attributeMap, ToscaTagNamesEnum.DESCRIPTION, desc -> attributeDef.setDescription(desc)); + ImportUtils.setField(attributeMap, ToscaTagNamesEnum.STATUS, status -> attributeDef.setStatus(status)); + Either<Object, ResultStatusEnum> eitherDefaultValue = ImportUtils.findToscaElement(attributeMap, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); + if (eitherDefaultValue.isLeft()) { + String attributeDefaultValue = getPropertyJsonStringValue(eitherDefaultValue.left().value(), attributeDef.getType()); + attributeDef.setDefaultValue(attributeDefaultValue); + } + Either<Object, ResultStatusEnum> eitherValue = ImportUtils.findToscaElement(attributeMap, ToscaTagNamesEnum.VALUE, ToscaElementTypeEnum.ALL); + if (eitherValue.isLeft()) { + String attributeValue = getPropertyJsonStringValue(eitherValue.left().value(), attributeDef.getType()); + attributeDef.setValue(attributeValue); + } + ImportUtils.setAttributeScheme(attributeMap, attributeDef); + return attributeDef; + } + + private static void setPropertyFieldStatus(Map<String, Object> propertyValue, PropertyDefinition propertyDef) { + Either<String, ResultStatusEnum> propertyFieldIsStatus = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.STATUS); + if (propertyFieldIsStatus.isLeft()) { + propertyDef.setStatus(propertyFieldIsStatus.left().value()); + } + + } + + private static void setAttributeFieldStatus(Map<String, Object> propertyValue, AttributeDefinition propertyDef) { + Either<String, ResultStatusEnum> propertyFieldIsStatus = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.STATUS); + if (propertyFieldIsStatus.isLeft()) { + propertyDef.setStatus(propertyFieldIsStatus.left().value()); + } + + } + + private static void setPropertyScheme(Map<String, Object> propertyValue, PropertyDefinition propertyDefinition) { + Either<SchemaDefinition, ResultStatusEnum> eitherSchema = getSchema(propertyValue); + if (eitherSchema.isLeft()) { + SchemaDefinition schemaDef = new SchemaDefinition(); + schemaDef.setProperty(eitherSchema.left().value().getProperty()); + propertyDefinition.setSchema(schemaDef); + } + + } + + private static void setAttributeScheme(Map<String, Object> propertyValue, AttributeDefinition propertyDefinition) { + Either<SchemaDefinition, ResultStatusEnum> eitherSchema = getSchema(propertyValue); + if (eitherSchema.isLeft()) { + SchemaDefinition schemaDef = new SchemaDefinition(); + schemaDef.setProperty(eitherSchema.left().value().getProperty()); + propertyDefinition.setSchema(schemaDef); + } + + } + + private static Either<SchemaDefinition, ResultStatusEnum> getSchema(Map<String, Object> propertyValue) { + Either<SchemaDefinition, ResultStatusEnum> result = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Object, ResultStatusEnum> propertyFieldEntryScheme = findToscaElement(propertyValue, ToscaTagNamesEnum.ENTRY_SCHEMA, ToscaElementTypeEnum.ALL); + if (propertyFieldEntryScheme.isLeft()) { + if (propertyFieldEntryScheme.left().value() instanceof String) { + String schemaType = (String) propertyFieldEntryScheme.left().value(); + SchemaDefinition schema = new SchemaDefinition(); + PropertyDefinition schemeProperty = new PropertyDefinition(); + schemeProperty.setType(schemaType); + schema.setProperty(schemeProperty); + result = Either.left(schema); + + } else if (propertyFieldEntryScheme.left().value() instanceof Map) { + PropertyDefinition schemeProperty = createModuleProperty((Map<String, Object>) propertyFieldEntryScheme.left().value()); + SchemaDefinition schema = new SchemaDefinition(); + schema.setProperty(schemeProperty); + result = Either.left(schema); + + } + + } + return result; + } + + private static void setPropertyFieldIsPassword(Map<String, Object> propertyValue, PropertyDefinition dataDefinition) { + Either<String, ResultStatusEnum> propertyFieldIsPassword = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.IS_PASSWORD); + if (propertyFieldIsPassword.isLeft()) { + dataDefinition.setPassword(Boolean.parseBoolean(propertyFieldIsPassword.left().value())); + } + } + + private static ResultStatusEnum setPropertyFieldDefaultValue(Map<String, Object> propertyValue, PropertyDefinition dataDefinition) { + Either<Object, ResultStatusEnum> propertyFieldDefaultValue = findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); + Gson gson = GsonFactory.getGson(); + if (propertyFieldDefaultValue.isLeft()) { + Object defaultValue = propertyFieldDefaultValue.left().value(); + String type = dataDefinition.getType(); + ToscaPropertyType innerToscaType = ToscaPropertyType.isValidType(type); + // esofer - supporting customized data types. The validation of the + // type will be in the creation of the property. + // if(innerToscaType == null){ + // return ResultStatusEnum.MISSING_ENTRY_SCHEMA_TYPE; + // } + // customized data types value is represented as json. + // Also customized data types which are scalar ones, for example, + // data type which derived from integer, their value will be + // represented as json. + if (innerToscaType == null || innerToscaType.equals(ToscaPropertyType.LIST) || innerToscaType.equals(ToscaPropertyType.MAP)) { + String jsonObj = null; + if (defaultValue != null) { + jsonObj = gson.toJson(defaultValue); + } + + dataDefinition.setDefaultValue(jsonObj); + } else { + dataDefinition.setDefaultValue(String.valueOf(defaultValue)); + } + + } + + return ResultStatusEnum.OK; + } + + private static ResultStatusEnum setAttributeFieldDefaultValue(Map<String, Object> propertyValue, AttributeDefinition dataDefinition) { + Either<Object, ResultStatusEnum> propertyFieldDefaultValue = findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); + Gson gson = GsonFactory.getGson(); + if (propertyFieldDefaultValue.isLeft()) { + Object defaultValue = propertyFieldDefaultValue.left().value(); + String type = dataDefinition.getType(); + ToscaPropertyType innerToscaType = ToscaPropertyType.isValidType(type); + // esofer - supporting customized data types. The validation of the + // type will be in the creation of the property. + // if(innerToscaType == null){ + // return ResultStatusEnum.MISSING_ENTRY_SCHEMA_TYPE; + // } + // customized data types value is represented as json. + // Also customized data types which are scalar ones, for example, + // data type which derived from integer, their value will be + // represented as json. + if (innerToscaType == null || innerToscaType.equals(ToscaPropertyType.LIST) || innerToscaType.equals(ToscaPropertyType.MAP)) { + String jsonObj = null; + if (defaultValue != null) { + jsonObj = gson.toJson(defaultValue); + } + + dataDefinition.setDefaultValue(jsonObj); + } else { + dataDefinition.setDefaultValue(String.valueOf(defaultValue)); + } + + } + + return ResultStatusEnum.OK; + } + + public static void setField(Map<String, Object> toscaJson, ToscaTagNamesEnum tagName, Consumer<String> setter) { + Either<String, ResultStatusEnum> fieldStringValue = findFirstToscaStringElement(toscaJson, tagName); + if (fieldStringValue.isLeft()) { + setter.accept(fieldStringValue.left().value()); + } + + } + + private static void setPropertyFieldDescription(Map<String, Object> propertyValue, PropertyDefinition dataDefinition) { + Either<String, ResultStatusEnum> propertyFieldDescription = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.DESCRIPTION); + if (propertyFieldDescription.isLeft()) { + dataDefinition.setDescription(propertyFieldDescription.left().value()); + } + } + + private static void setPropertyFieldRequired(Map<String, Object> propertyValue, PropertyDefinition dataDefinition) { + Either<String, ResultStatusEnum> propertyFieldRequired = findFirstToscaBooleanElement(propertyValue, ToscaTagNamesEnum.REQUIRED); + if (propertyFieldRequired.isLeft()) { + dataDefinition.setRequired(Boolean.parseBoolean(propertyFieldRequired.left().value())); + } + } + + private static void setAttributeFieldType(Map<String, Object> propertyValue, AttributeDefinition dataDefinition) { + Either<String, ResultStatusEnum> propertyFieldType = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.TYPE); + if (propertyFieldType.isLeft()) { + dataDefinition.setType(propertyFieldType.left().value()); + } + } + + private static void setPropertyFieldType(Map<String, Object> propertyValue, PropertyDefinition dataDefinition) { + Either<String, ResultStatusEnum> propertyFieldType = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.TYPE); + if (propertyFieldType.isLeft()) { + dataDefinition.setType(propertyFieldType.left().value()); + } + } + + private static void setAttributeFieldDescription(Map<String, Object> propertyValue, AttributeDefinition dataDefinition) { + Either<String, ResultStatusEnum> propertyFieldDescription = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.DESCRIPTION); + if (propertyFieldDescription.isLeft()) { + dataDefinition.setDescription(propertyFieldDescription.left().value()); + } + } + + public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getProperties(Map<String, Object> toscaJson) { + Function<String, PropertyDefinition> elementGenByName = elementName -> createProperties(elementName); + Function<Map<String, Object>, PropertyDefinition> func = map -> createModuleProperty(map); + + return getElements(toscaJson, ToscaTagNamesEnum.PROPERTIES, elementGenByName, func); + + } + + public static Either<Map<String, InputDefinition>, ResultStatusEnum> getInputs(Map<String, Object> toscaJson) { + Function<String, InputDefinition> elementGenByName = elementName -> createInputs(elementName); + Function<Map<String, Object>, InputDefinition> func = map -> createModuleInput(map); + + return getElements(toscaJson, ToscaTagNamesEnum.INPUTS, elementGenByName, func); + + } + + public static Either<Map<String, AttributeDefinition>, ResultStatusEnum> getAttributes(Map<String, Object> toscaJson) { + Function<String, AttributeDefinition> elementGenByName = elementName -> createAttribute(elementName); + Function<Map<String, Object>, AttributeDefinition> func = map -> createModuleAttribute(map); + + return getElements(toscaJson, ToscaTagNamesEnum.ATTRIBUTES, elementGenByName, func); + } + + public static <ElementDefinition> Either<Map<String, ElementDefinition>, ResultStatusEnum> getElements(Map<String, Object> toscaJson, ToscaTagNamesEnum elementTagName, Function<String, ElementDefinition> elementGenByName, + Function<Map<String, Object>, ElementDefinition> func) { + Either<Map<String, ElementDefinition>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Map<String, Object>, ResultStatusEnum> toscaAttributes = findFirstToscaMapElement(toscaJson, elementTagName); + if (toscaAttributes.isLeft()) { + Map<String, Object> jsonAttributes = toscaAttributes.left().value(); + Map<String, ElementDefinition> moduleAttributes = new HashMap<>(); + Iterator<Entry<String, Object>> propertiesNameValue = jsonAttributes.entrySet().iterator(); + while (propertiesNameValue.hasNext()) { + Entry<String, Object> attributeNameValue = propertiesNameValue.next(); + if (attributeNameValue.getValue() instanceof Map) { + @SuppressWarnings("unchecked") + ElementDefinition attribute = func.apply((Map<String, Object>) attributeNameValue.getValue()); + moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), attribute); + } else { + + ElementDefinition element = elementGenByName.apply(String.valueOf(attributeNameValue.getValue())); + + moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), element); + } + + } + + if (moduleAttributes.size() > 0) { + eitherResult = Either.left(moduleAttributes); + } + + } + return eitherResult; + + } + + private static AttributeDefinition createAttribute(String name) { + AttributeDefinition attribute = new AttributeDefinition(); + + attribute.setName(name); + return attribute; + } + + private static PropertyDefinition createProperties(String name) { + PropertyDefinition property = new PropertyDefinition(); + property.setDefaultValue(name); + property.setName(name); + return property; + } + + private static InputDefinition createInputs(String name) { + InputDefinition input = new InputDefinition(); + + input.setName(name); + return input; + } + + public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParameters(Map<String, Object> heatData, String artifactType) { + + Either<List<HeatParameterDefinition>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND); + Either<Map<String, Object>, ResultStatusEnum> toscaProperties = findFirstToscaMapElement(heatData, ToscaTagNamesEnum.PARAMETERS); + if (toscaProperties.isLeft()) { + Map<String, Object> jsonProperties = toscaProperties.left().value(); + List<HeatParameterDefinition> moduleProperties = new ArrayList<>(); + Iterator<Entry<String, Object>> propertiesNameValue = jsonProperties.entrySet().iterator(); + while (propertiesNameValue.hasNext()) { + Entry<String, Object> propertyNameValue = propertiesNameValue.next(); + if (propertyNameValue.getValue() instanceof Map) { + if (!artifactType.equals(ArtifactTypeEnum.HEAT_ENV.getType())) { + @SuppressWarnings("unchecked") + Either<HeatParameterDefinition, ResultStatusEnum> propertyStatus = createModuleHeatParameter((Map<String, Object>) propertyNameValue.getValue()); + if (propertyStatus.isRight()) { + return Either.right(propertyStatus.right().value()); + } + HeatParameterDefinition property = propertyStatus.left().value(); + property.setName(String.valueOf(propertyNameValue.getKey())); + moduleProperties.add(property); + } else { + addHeatParamDefinition(moduleProperties, propertyNameValue, true); + } + } else { + addHeatParamDefinition(moduleProperties, propertyNameValue, false); + } + + } + + if (moduleProperties.size() > 0) { + eitherResult = Either.left(moduleProperties); + } + + } + return eitherResult; + + } + + private static void addHeatParamDefinition(List<HeatParameterDefinition> moduleProperties, Entry<String, Object> propertyNameValue, boolean isJson) { + HeatParameterDefinition property = new HeatParameterDefinition(); + Object value = propertyNameValue.getValue(); + if (value != null) { + property.setDefaultValue(isJson ? new Gson().toJson(value).toString() : StringEscapeUtils.escapeJava(String.valueOf(value))); + } + property.setName(String.valueOf(propertyNameValue.getKey())); + moduleProperties.add(property); + } + + private static Either<HeatParameterDefinition, ResultStatusEnum> createModuleHeatParameter(Map<String, Object> propertyValue) { + HeatParameterDefinition propertyDef = new HeatParameterDefinition(); + String type; + Either<String, ResultStatusEnum> propertyFieldType = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.TYPE); + if (propertyFieldType.isLeft()) { + type = propertyFieldType.left().value(); + propertyDef.setType(type); + } else { + return Either.right(ResultStatusEnum.INVALID_PROPERTY_TYPE); + } + Either<String, ResultStatusEnum> propertyFieldDescription = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.DESCRIPTION); + if (propertyFieldDescription.isLeft()) { + propertyDef.setDescription(propertyFieldDescription.left().value()); + } + + Either<Object, ResultStatusEnum> propertyFieldDefaultVal = findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); + if (propertyFieldDefaultVal.isLeft()) { + if (propertyFieldDefaultVal.left().value() == null) { + return Either.right(ResultStatusEnum.INVALID_PROPERTY_VALUE); + } + Object value = propertyFieldDefaultVal.left().value(); + String defaultValue = type.equals(HeatParameterType.JSON.getType()) ? new Gson().toJson(value).toString() : StringEscapeUtils.escapeJava(String.valueOf(value)); + propertyDef.setDefaultValue(defaultValue); + propertyDef.setCurrentValue(defaultValue); + } + + return Either.left(propertyDef); + } + + public static String getPropertyJsonStringValue(Object value, String type) { + Gson gson = new Gson(); + if (type == null) { + return null; + } + ToscaPropertyType validType = ToscaPropertyType.isValidType(type); + if (validType == null || validType.equals(ToscaPropertyType.MAP) || validType.equals(ToscaPropertyType.LIST)) { + return gson.toJson(value); + } + return value.toString(); + } + + /** + * removes from Json map (toscaJson) first element found by name (elementName) note that this method could update the received argument toscaJson + * + * @param toscaJson + * @param elementName + */ + public static void removeElementFromJsonMap(Map<String, Object> toscaJson, String elementName) { + for (Entry<String, Object> entry : toscaJson.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (key.equals(elementName)) { + toscaJson.remove(elementName); + return; + } else if (value instanceof Map) { + removeElementFromJsonMap((Map<String, Object>) value, elementName); + } + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InformationDeployedArtifactsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InformationDeployedArtifactsBusinessLogic.java new file mode 100644 index 0000000000..129110e13f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InformationDeployedArtifactsBusinessLogic.java @@ -0,0 +1,117 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.apache.commons.codec.binary.Base64; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.Configuration.DeploymentArtifactTypeConfig; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +//Pavel +//currently NOT IN USE - there are no informational deployed artifacts after US601880 + +@org.springframework.stereotype.Component("informationDeployedArtifactsBusinessLogic") +public class InformationDeployedArtifactsBusinessLogic { + + /* + * private static Logger log = LoggerFactory.getLogger(InformationDeployedArtifactsBusinessLogic.class. getName()); + * + * @javax.annotation.Resource private ArtifactsBusinessLogic artifactBusinessLogic; + * + * public boolean isInformationDeployedArtifact(ArtifactDefinition artifactInfo) { log.debug("checking if artifact {} is informationalDeployable", artifactInfo.getArtifactName()); boolean informationDeployedArtifact = false; Map<String, + * DeploymentArtifactTypeConfig> resourceInformationalDeployedArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration() .getResourceInformationalDeployedArtifacts(); if( resourceInformationalDeployedArtifacts != null && + * resourceInformationalDeployedArtifacts.containsKey(artifactInfo. getArtifactType())){ if( artifactInfo.getArtifactGroupType() == ArtifactGroupTypeEnum.INFORMATIONAL && artifactInfo.checkEsIdExist()){ informationDeployedArtifact = true; + * + * } } String message = (informationDeployedArtifact) ? "artifact {} is informationalDeployable" : "artifact {} is not informationalDeployable"; log.debug(message, artifactInfo.getArtifactName()); return informationDeployedArtifact; } + * + * public Either<Boolean, ResponseFormat> validateArtifact(boolean isCreate, ArtifactDefinition artifactInfo, Component parent, NodeTypeEnum parentType) { + * + * log.debug("checking if informationalDeployable artifact {} is valid ", artifactInfo.getArtifactName()); Wrapper<ResponseFormat> responseFormatWrapper = new Wrapper<ResponseFormat>(); Map<String, DeploymentArtifactTypeConfig> + * resourceInformationalDeployedArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration(). getResourceInformationalDeployedArtifacts(); + * + * + * artifactBusinessLogic.validateArtifactTypeExists(responseFormatWrapper, artifactInfo); if( responseFormatWrapper.isEmpty() && isCreate ){ artifactBusinessLogic.validateSingleArtifactType(responseFormatWrapper, + * ArtifactTypeEnum.findType(artifactInfo.getArtifactType()), parent, parentType); } if( responseFormatWrapper.isEmpty() ){ ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifactInfo.getArtifactType()); + * artifactBusinessLogic.validateFileExtension(responseFormatWrapper, () -> resourceInformationalDeployedArtifacts.get(artifactInfo.getArtifactType() ), artifactInfo, parentType, artifactType); } + * + * if( responseFormatWrapper.isEmpty() ){ validatePayloadContent(responseFormatWrapper, artifactInfo); } + * + * Either<Boolean, ResponseFormat> response; if( responseFormatWrapper.isEmpty() ){ response = Either.left(true); } else{ response = Either.right(responseFormatWrapper.getInnerElement()); } + * + * String message = (response.isLeft()) ? "informationalDeployable artifact {} is valid" : "informationalDeployable artifact {} is not valid"; log.debug(message, artifactInfo.getArtifactName()); return response; } + * + * private void validatePayloadContent(Wrapper<ResponseFormat> responseFormatWrapper, ArtifactDefinition artifactToVerify) { ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifactToVerify.getArtifactType()); if( artifactType == + * ArtifactTypeEnum.YANG_XML ){ String rawPayloadData = artifactToVerify.getPayloadData(); String xmlToParse = Base64.isBase64(rawPayloadData) ? new String(org.apache.commons.codec.binary.Base64.decodeBase64(rawPayloadData )) : rawPayloadData; + * + * boolean isXmlValid = artifactBusinessLogic.isValidXml(xmlToParse.getBytes()); if( !isXmlValid ){ ResponseFormat responseFormat = ResponseFormatManager.getInstance().getResponseFormat(ActionStatus. INVALID_XML, + * artifactToVerify.getArtifactType()); responseFormatWrapper.setInnerElement(responseFormat); log.debug("Xml is not valid for artifact : {}", artifactToVerify.getArtifactName()); } } } + * + * + * + * + * public List<ArtifactDefinition> getInformationalDeployedArtifactsForResourceInstance( ComponentInstance resourceInstance ) { String resourceUid = resourceInstance.getComponentUid(); String resourceName = resourceInstance.getComponentName(); + * return getInformationalDeployedArtifactsForResource(resourceUid, resourceName); } + * + * private List<ArtifactDefinition> getInformationalDeployedArtifactsForResource( String resourceUid, String resourceName) { List<ArtifactDefinition> informationalDeployedArtifacts = new ArrayList<ArtifactDefinition>(); log. + * debug("checking if informationalDeployable artifacts exist for resource {} " , resourceName); Map<String, DeploymentArtifactTypeConfig> resourceInformationalDeployedArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration() + * .getResourceInformationalDeployedArtifacts(); + * + * + * Either<Map<String, ArtifactDefinition>, StorageOperationStatus> eitherArtifacts = artifactBusinessLogic.getArtifacts(resourceUid, NodeTypeEnum.Resource, false, ArtifactGroupTypeEnum.INFORMATIONAL); + * + * if( eitherArtifacts.isLeft() && resourceInformationalDeployedArtifacts != null ){ Predicate<ArtifactDefinition> predicate = p -> resourceInformationalDeployedArtifacts.containsKey(p.getArtifactType()) && p.checkEsIdExist() && + * p.getArtifactGroupType() == ArtifactGroupTypeEnum.INFORMATIONAL; informationalDeployedArtifacts = eitherArtifacts.left().value().values().stream().filter( predicate ).collect(Collectors.toList()); } + * + * if( informationalDeployedArtifacts.isEmpty() ){ log.debug("no informationalDeployable artifacts exist for resource {} ", resourceName); } else{ log. debug("informationalDeployable artifacts found for resource {} are :{}", resourceName, + * informationalDeployedArtifacts.toString()); } + * + * + * return informationalDeployedArtifacts; } + * + * public List<ArtifactDefinition> getAllDeployableArtifacts( Resource resource ){ List<ArtifactDefinition> merged = new ArrayList<ArtifactDefinition>(); + * + * List<ArtifactDefinition> deploymentArtifacts = artifactBusinessLogic.getDeploymentArtifacts(resource, NodeTypeEnum.Resource); merged.addAll(deploymentArtifacts); + * + * List<ArtifactDefinition> informationalDeployedArtifactsForResource = getInformationalDeployedArtifactsForResource( resource.getUniqueId(), resource.getName()); merged.addAll(informationalDeployedArtifactsForResource); + * + * return merged; } + */ +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java new file mode 100644 index 0000000000..7d0624440e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -0,0 +1,526 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.InputsOperation; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; +import org.openecomp.sdc.be.resources.data.InputsData; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("inputsBusinessLogic") +public class InputsBusinessLogic extends BaseBusinessLogic { + + private static final String CREATE_INPUT = "CreateInput"; + + private static Logger log = LoggerFactory.getLogger(InputsBusinessLogic.class.getName()); + + @Autowired + private IResourceOperation resourceOperation = null; + + @javax.annotation.Resource + private InputsOperation inputsOperation = null; + + @javax.annotation.Resource + private PropertyOperation propertyOperation = null; + + @Autowired + private ComponentsUtils componentsUtils; + + /** + * associate inputs to a given component with paging + * + * @param componentId + * @param userId + * @param fromId + * @param amount + * @return + */ + public Either<List<InputDefinition>, ResponseFormat> getInputs(String userId, String componentId, String fromName, + int amount) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Inputs", false); + + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<List<InputDefinition>, StorageOperationStatus> inputsEitherRes = inputsOperation + .getInputsOfComponent(componentId, fromName, amount); + if (inputsEitherRes.isRight()) { + if (inputsEitherRes.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + return Either.left(new ArrayList<InputDefinition>()); + } + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(inputsEitherRes.right().value()); + log.debug("Failed to get inputs under component {}, error: {}", componentId, actionStatus.name()); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + + } + + return Either.left(inputsEitherRes.left().value()); + + } + + /** + * associate properties to a given component instance input + * + * @param instanceId + * @param userId + * @param inputId + * @return + */ + + public Either<List<ComponentInstanceProperty>, ResponseFormat> getComponentInstancePropertiesByInputId( + String userId, String instanceId, String inputId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Properties by input", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<List<ComponentInstanceProperty>, StorageOperationStatus> propertiesEitherRes = inputsOperation + .getComponentInstancePropertiesByInputId(instanceId, inputId); + if (propertiesEitherRes.isRight()) { + + if (propertiesEitherRes.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + return Either.left(new ArrayList<ComponentInstanceProperty>()); + } + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(propertiesEitherRes.right().value()); + log.debug("Failed to get inputs under component {}, error: {}", instanceId, actionStatus.name()); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + + } + + return Either.left(propertiesEitherRes.left().value()); + + } + + public Either<List<ComponentInstanceInput>, ResponseFormat> getInputsForComponentInput(String userId, + String componentId, String inputId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Inputs by input", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<List<ComponentInstanceInput>, StorageOperationStatus> inputsEitherRes = inputsOperation + .getComponentInstanceInputsByInputId(componentId, inputId); + if (inputsEitherRes.isRight()) { + + if (inputsEitherRes.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + return Either.left(new ArrayList<ComponentInstanceInput>()); + } + + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(inputsEitherRes.right().value()); + log.debug("Failed to get inputs for input under component {}, error: {}", componentId, actionStatus.name()); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + + } + + return Either.left(inputsEitherRes.left().value()); + + } + + public Either<List<InputDefinition>, ResponseFormat> createMultipleInputs(String userId, String componentId, + ComponentTypeEnum componentType, ComponentInstInputsMap componentInstInputsMapUi, boolean shouldLockComp, + boolean inTransaction) { + + Either<List<InputDefinition>, ResponseFormat> result = null; + org.openecomp.sdc.be.model.Component component = null; + try { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Properties by input", false); + + if (resp.isRight()) { + result = Either.right(resp.right().value()); + return result; + } + + User user = resp.left().value(); + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreArtifacts(false); + componentParametersView.setIgnoreUsers(false); + + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists( + componentId, componentType, componentParametersView, userId, null, user); + + if (validateComponent.isRight()) { + result = Either.right(validateComponent.right().value()); + return result; + } + component = validateComponent.left().value(); + + if (shouldLockComp) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, CREATE_INPUT); + if (lockComponent.isRight()) { + result = Either.right(lockComponent.right().value()); + return result; + } + } + + Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId); + if (canWork.isRight()) { + result = Either.right(canWork.right().value()); + return result; + } + + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes( + applicationDataTypeCache); + if (allDataTypes.isRight()) { + result = Either.right(allDataTypes.right().value()); + return result; + } + + Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); + + Either<List<InputDefinition>, StorageOperationStatus> createInputsResult = this.inputsOperation + .addInputsToComponent(componentId, componentType.getNodeType(), componentInstInputsMapUi, + dataTypes); + + if (createInputsResult.isRight()) { + ActionStatus actionStatus = componentsUtils + .convertFromStorageResponse(createInputsResult.right().value()); + log.debug("Failed to create inputs under component {}, error: {}", componentId, actionStatus.name()); + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + return result; + + } + result = Either.left(createInputsResult.left().value()); + + return result; + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + + } + + } + + public Either<List<InputDefinition>, ResponseFormat> createInputs(String componentId, String userId, + ComponentTypeEnum componentType, List<InputDefinition> inputsDefinitions, boolean shouldLockComp, + boolean inTransaction) { + + Either<List<InputDefinition>, ResponseFormat> result = null; + + org.openecomp.sdc.be.model.Component component = null; + try { + + if (inputsDefinitions != null && false == inputsDefinitions.isEmpty()) { + + if (shouldLockComp == true && inTransaction == true) { + BeEcompErrorManager.getInstance().logInternalFlowError("createGroups", + "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); + // Cannot lock component since we are in a middle of another + // transaction. + ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; + result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + return result; + } + + Either<User, ResponseFormat> validateUserExists = validateUserExists(userId, CREATE_INPUT, true); + if (validateUserExists.isRight()) { + result = Either.right(validateUserExists.right().value()); + return result; + } + + User user = validateUserExists.left().value(); + + Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists( + componentId, componentType, inTransaction, false); + if (validateComponent.isRight()) { + result = Either.right(validateComponent.right().value()); + return result; + } + component = validateComponent.left().value(); + + if (shouldLockComp) { + Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, CREATE_INPUT); + if (lockComponent.isRight()) { + return Either.right(lockComponent.right().value()); + } + } + + Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId); + if (canWork.isRight()) { + result = Either.right(canWork.right().value()); + return result; + } + + result = createInputsInGraph(inputsDefinitions, component, user, inTransaction); + } + + return result; + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } + + } + + } + + public Either<List<InputDefinition>, ResponseFormat> createInputsInGraph(List<InputDefinition> inputsDefinitions, + org.openecomp.sdc.be.model.Component component, User user, boolean inTransaction) { + Either<List<InputDefinition>, ResponseFormat> result; + List<InputDefinition> inputs = new ArrayList<InputDefinition>(); + for (InputDefinition inputDefinition : inputsDefinitions) { + // String resourceId, String inputName, InputDefinition + // newInputDefinition, String userId, boolean inTransaction + Either<InputDefinition, ResponseFormat> createInput = createInput(component, user, + component.getComponentType(), inputDefinition.getName(), inputDefinition, inTransaction); + if (createInput.isRight()) { + log.debug("Failed to create group {}.", createInput); + result = Either.right(createInput.right().value()); + return result; + } + InputDefinition createdGroup = createInput.left().value(); + inputs.add(createdGroup); + } + result = Either.left(inputs); + return result; + } + + /** + * Delete input from service + * + * @param component + * @param user + * @param componentType + * @param inputId + * @param inTransaction + * @return + */ + public Either<InputDefinition, ResponseFormat> deleteInput(String componentType, String componentId, String userId, String inputId, boolean inTransaction) { + + if (log.isDebugEnabled()) + log.debug("Going to delete input id: {}", inputId); + + // Validate user (exists) + Either<User, ResponseFormat> userEither = validateUserExists(userId, "Delete input", true); + if (userEither.isRight()) { + return Either.right(userEither.right().value()); + } + + // Get component using componentType, componentId + Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentEither = serviceOperation.getComponent(componentId, true); + if (componentEither.isRight()) { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentEither.right().value()))); + } + org.openecomp.sdc.be.model.Component component = componentEither.left().value(); + + // Validate inputId is child of the component + // And get the inputDefinition for the response + InputDefinition inputDefinition = null; + Optional<InputDefinition> optionalInput = component.getInputs().stream(). + // filter by ID + filter(input -> input.getUniqueId().equals(inputId)). + // Get the input + findAny(); + if (optionalInput.isPresent()) { + inputDefinition = optionalInput.get(); + } else { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId)); + } + + // Lock component + Either<Boolean, ResponseFormat> lockResultEither = lockComponent(componentId, component, "deleteInput"); + if (lockResultEither.isRight()) { + ResponseFormat responseFormat = lockResultEither.right().value(); + return Either.right(responseFormat); + } + + // Delete input operations + Either<String, StorageOperationStatus> deleteEither = Either.right(StorageOperationStatus.GENERAL_ERROR); + try { + deleteEither = inputsOperation.deleteInput(inputId); + if (deleteEither.isRight()){ + log.debug("Component id: {} delete input id: {} failed", componentId, inputId); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteEither.right().value()), component.getName())); + } + return Either.left(inputDefinition); + } finally { + if (deleteEither.isRight()) { + log.debug("Component id: {} delete input id: {} failed", componentId, inputId); + titanGenericDao.rollback(); + } else { + log.debug("Component id: {} delete input id: {} success", componentId, inputId); + titanGenericDao.commit(); + } + unlockComponent(deleteEither, component); + } + } + + /** + * Create new property on resource in graph + * + * @param resourceId + * @param propertyName + * @param newPropertyDefinition + * @param userId + * @return Either<PropertyDefinition, ActionStatus> + */ + + private Either<InputDefinition, ResponseFormat> createInput(org.openecomp.sdc.be.model.Component component, + User user, ComponentTypeEnum componentType, String inputName, InputDefinition newInputDefinition, + boolean inTransaction) { + + Either<InputDefinition, ResponseFormat> result = null; + if (log.isDebugEnabled()) + log.debug("Going to create input {}", newInputDefinition); + + try { + + // verify property not exist in resource + List<InputDefinition> resourceProperties = component.getInputs(); + + if (resourceProperties != null) { + if (inputsOperation.isInputExist(resourceProperties, component.getUniqueId(), inputName)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, "")); + } + } + + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes( + applicationDataTypeCache); + if (allDataTypes.isRight()) { + return Either.right(allDataTypes.right().value()); + } + + Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); + + // validate input default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, + dataTypes); + if (defaultValuesValidation.isRight()) { + return Either.right(defaultValuesValidation.right().value()); + } + // convert property + ToscaPropertyType type = getType(newInputDefinition.getType()); + PropertyValueConverter converter = type.getConverter(); + // get inner type + String innerType = null; + if (newInputDefinition != null) { + SchemaDefinition schema = newInputDefinition.getSchema(); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (prop != null) { + innerType = prop.getType(); + } + } + String convertedValue = null; + if (newInputDefinition.getDefaultValue() != null) { + convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, + allDataTypes.left().value()); + newInputDefinition.setDefaultValue(convertedValue); + } + } + + // add the new property to resource on graph + // need to get StorageOpaerationStatus and convert to ActionStatus + // from componentsUtils + Either<InputsData, StorageOperationStatus> either = inputsOperation.addInput(inputName, newInputDefinition, + component.getUniqueId(), componentType.getNodeType()); + if (either.isRight()) { + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(either.right().value()), component.getName())); + } + // @TODO commit + // inputsOperation.getTitanGenericDao().commit(); + InputDefinition createdInputyDefinition = inputsOperation + .convertInputDataToInputDefinition(either.left().value()); + createdInputyDefinition.setName(inputName); + createdInputyDefinition.setParentUniqueId(component.getUniqueId()); + + return Either.left(createdInputyDefinition); + + } finally { + + if (false == inTransaction) { + + if (result == null || result.isRight()) { + log.debug("Going to execute rollback on create group."); + titanGenericDao.rollback(); + } else { + log.debug("Going to execute commit on create group."); + titanGenericDao.commit(); + } + + } + + } + + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceLifecycleTypeImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceLifecycleTypeImportManager.java new file mode 100644 index 0000000000..780980ba08 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceLifecycleTypeImportManager.java @@ -0,0 +1,124 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.operations.api.IInterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("interfaceLifecycleTypeImportManager") +public class InterfaceLifecycleTypeImportManager { + + @Resource + private IInterfaceLifecycleOperation interfaceLifecycleOperation; + + @Resource + private ComponentsUtils componentsUtils; + @Resource + private CommonImportManager commonImportManager; + + private static Logger log = LoggerFactory.getLogger(InterfaceLifecycleTypeImportManager.class.getName()); + + public Either<List<InterfaceDefinition>, ResponseFormat> createLifecycleTypes(String interfaceLifecycleTypesYml) { + + Either<List<InterfaceDefinition>, ActionStatus> interfaces = createLifecyclyTypeFromYml(interfaceLifecycleTypesYml); + if (interfaces.isRight()) { + ActionStatus status = interfaces.right().value(); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByGroupType(status, null); + return Either.right(responseFormat); + } + return createInterfacesByDao(interfaces.left().value()); + + } + + private Either<List<InterfaceDefinition>, ActionStatus> createLifecyclyTypeFromYml(String interfaceLifecycleTypesYml) { + return commonImportManager.createElementTypesFromYml(interfaceLifecycleTypesYml, (lifecycleTypeName, lifecycleTypeJsonData) -> createLifecycleType(lifecycleTypeName, lifecycleTypeJsonData)); + + } + + private Either<List<InterfaceDefinition>, ResponseFormat> createInterfacesByDao(List<InterfaceDefinition> interfacesToCreate) { + List<InterfaceDefinition> createdInterfaces = new ArrayList<>(); + Either<List<InterfaceDefinition>, ResponseFormat> eitherResult = Either.left(createdInterfaces); + Iterator<InterfaceDefinition> interfaceItr = interfacesToCreate.iterator(); + boolean stopDao = false; + while (interfaceItr.hasNext() && !stopDao) { + InterfaceDefinition interfaceDef = interfaceItr.next(); + + log.info("send interfaceDefinition {} to dao for create", interfaceDef.getType()); + + Either<InterfaceDefinition, StorageOperationStatus> dataModelResponse = interfaceLifecycleOperation.createInterfaceType(interfaceDef); + if (dataModelResponse.isRight()) { + log.info("failed to create interface : {} error: {}", interfaceDef.getType(), dataModelResponse.right().value().name()); + if (dataModelResponse.right().value() != StorageOperationStatus.SCHEMA_VIOLATION) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponseForLifecycleType(dataModelResponse.right().value()), interfaceDef.getType()); + eitherResult = Either.right(responseFormat); + stopDao = true; + } + + } else { + createdInterfaces.add(dataModelResponse.left().value()); + } + if (!interfaceItr.hasNext()) { + log.info("lifecycle types were created successfully!!!"); + } + } + return eitherResult; + } + + private InterfaceDefinition createLifecycleType(String interfaceDefinition, Map<String, Object> toscaJson) { + InterfaceDefinition interfaceDef = new InterfaceDefinition(); + interfaceDef.setType(interfaceDefinition); + + Map<String, Operation> operations = new HashMap<String, Operation>(); + + for (Map.Entry<String, Object> entry : toscaJson.entrySet()) { + Operation operation = new Operation(); + Map<String, Object> opProp = (Map<String, Object>) entry.getValue(); + + operation.setDescription((String) opProp.get("description")); + operations.put(entry.getKey(), operation); + } + interfaceDef.setOperations(operations); + return interfaceDef; + } + + public static void setLog(Logger log) { + InterfaceLifecycleTypeImportManager.log = log; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/MonitoringBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/MonitoringBusinessLogic.java new file mode 100644 index 0000000000..e9708f50d5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/MonitoringBusinessLogic.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.impl.MonitoringDao; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.common.monitoring.MonitoringEvent; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("monitoringBusinessLogic") +public class MonitoringBusinessLogic { + + private static Logger log = LoggerFactory.getLogger(MonitoringBusinessLogic.class.getName()); + + @javax.annotation.Resource + private MonitoringDao monitoringDao; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + public Either<Boolean, ResponseFormat> logMonitoringEvent(MonitoringEvent monitoringEvent) { + if (monitoringDao == null) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + ActionStatus status = monitoringDao.addRecord(monitoringEvent); + if (!status.equals(ActionStatus.OK)) { + log.warn("Failed to persist monitoring event: {}", status.name()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + return Either.left(true); + } + + public String getEsHost() { + + String res = monitoringDao.getEsHost(); + res = res.replaceAll("[\\[\\]]", ""); + res = res.split(",")[0]; + res = res.replaceAll("[']", ""); + res = res.split(":")[0]; + return res; + } + + public String getEsPort() { + return monitoringDao.getEsPort(); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PolicyTypeImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PolicyTypeImportManager.java new file mode 100644 index 0000000000..1e0670daa2 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PolicyTypeImportManager.java @@ -0,0 +1,130 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.CommonImportManager.ElementTypeEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.PolicyTypeDefinition; +import org.openecomp.sdc.be.model.operations.api.IGroupOperation; +import org.openecomp.sdc.be.model.operations.api.IPolicyTypeOperation; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("policyTypeImportManager") +public class PolicyTypeImportManager { + + @Resource + private PropertyOperation propertyOperation; + @Resource + private IPolicyTypeOperation policyTypeOperation; + @Resource + private ComponentsUtils componentsUtils; + @Resource + private IResourceOperation resourceOperation; + @Autowired + protected IGroupOperation groupOperation; + + @Resource + private CommonImportManager commonImportManager; + + public Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat> createPolicyTypes(String groupTypesYml) { + return commonImportManager.createElementTypes(groupTypesYml, elementTypeYml -> createPolicyTypesFromYml(elementTypeYml), groupTypesList -> createPolicyTypesByDao(groupTypesList), ElementTypeEnum.PolicyType); + } + + private Either<List<PolicyTypeDefinition>, ActionStatus> createPolicyTypesFromYml(String policyTypesYml) { + + return commonImportManager.createElementTypesFromYml(policyTypesYml, (policyTypeName, groupTypeJsonData) -> createPolicyType(policyTypeName, groupTypeJsonData)); + } + + private Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat> createPolicyTypesByDao(List<PolicyTypeDefinition> policyTypesToCreate) { + return commonImportManager.createElementTypesByDao(policyTypesToCreate, policyType -> validatePolicyType(policyType), policyType -> new ImmutablePair<>(ElementTypeEnum.PolicyType, policyType.getType()), + policyTypeName -> policyTypeOperation.getLatestPolicyTypeByType(policyTypeName), policyType -> policyTypeOperation.addPolicyType(policyType), null); + } + + private Either<ActionStatus, ResponseFormat> validatePolicyType(PolicyTypeDefinition policyType) { + Either<ActionStatus, ResponseFormat> result = Either.left(ActionStatus.OK); + if (policyType.getTargets() != null) { + if (policyType.getTargets().isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.TARGETS_EMPTY, policyType.getType()); + result = Either.right(responseFormat); + } + if (result.isLeft()) { + for (String targetName : policyType.getTargets()) { + boolean isValid = resourceOperation.getLatestByToscaResourceName(targetName, false).isLeft(); + if (!isValid) { + isValid = groupOperation.isGroupExist(targetName, false); + } + if (!isValid) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.TARGETS_NON_VALID, policyType.getType(), targetName); + result = Either.right(responseFormat); + break; + } + } + } + } + + return result; + } + + private PolicyTypeDefinition createPolicyType(String groupTypeName, Map<String, Object> toscaJson) { + + PolicyTypeDefinition policyType = new PolicyTypeDefinition(); + + if (toscaJson != null) { + // Description + final Consumer<String> descriptionSetter = description -> policyType.setDescription(description); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DESCRIPTION.getElementName(), descriptionSetter); + // Derived From + final Consumer<String> derivedFromSetter = derivedFrom -> policyType.setDerivedFrom(derivedFrom); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.DERIVED_FROM.getElementName(), derivedFromSetter); + // Properties + commonImportManager.setProperties(toscaJson, (values) -> policyType.setProperties(values)); + // Metadata + final Consumer<Map<String, String>> metadataSetter = metadata -> policyType.setMetadata(metadata); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.METADATA.getElementName(), metadataSetter); + // Targets + final Consumer<List<String>> targetsSetter = targets -> policyType.setTargets(targets); + commonImportManager.setField(toscaJson, ToscaTagNamesEnum.TARGETS.getElementName(), targetsSetter); + + policyType.setType(groupTypeName); + + policyType.setHighestVersion(true); + + policyType.setVersion(ImportUtils.Constants.FIRST_CERTIFIED_VERSION_VERSION); + } + return policyType; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ProductBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ProductBusinessLogic.java new file mode 100644 index 0000000000..3a54513b0b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ProductBusinessLogic.java @@ -0,0 +1,887 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ProductOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; + +@org.springframework.stereotype.Component("productBusinessLogic") +public class ProductBusinessLogic extends ComponentBusinessLogic { + + private static final String PRODUCT_FULL_NAME = "full"; + private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated"; + private static Logger log = LoggerFactory.getLogger(ProductBusinessLogic.class.getName()); + private static final String INITIAL_VERSION = "0.1"; + private static List<Role> creationRoles; + private static List<Role> updateRoles; + private static List<Role> contactsRoles; + + public ProductBusinessLogic() { + creationRoles = new ArrayList<>(); + updateRoles = new ArrayList<>(); + contactsRoles = new ArrayList<>(); + + // only PM is allowed to create/update products + creationRoles.add(Role.PRODUCT_MANAGER); + updateRoles.add(Role.PRODUCT_MANAGER); + // Only PM is allowed to be product contacts + contactsRoles.add(Role.PRODUCT_MANAGER); + } + + @Autowired + private IElementOperation elementDao; + + @Autowired + private ProductComponentInstanceBusinessLogic productComponentInstanceBusinessLogic; + + @Autowired + private ICacheMangerOperation cacheManagerOperation; + + public Either<Product, ResponseFormat> createProduct(Product product, User user) { + AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE; + ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT; + + // validate user - should be first to get the maximum auditing info in + // case of subsequent failures + log.debug("get user from DB"); + Either<User, ResponseFormat> eitherCreator = validateUser(user, "Create Product", product, actionEnum, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + // validate user role + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, product, creationRoles, actionEnum, null); + if (validateRes.isRight()) { + return Either.right(validateRes.right().value()); + } + + if (product == null) { + log.debug("Invalid product json. Check product servlet log for createProduct entry params"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + componentsUtils.auditComponentAdmin(responseFormat, user, product, Constants.EMPTY_STRING, Constants.EMPTY_STRING, actionEnum, typeEnum); + return Either.right(responseFormat); + } + + // warn about non-updatable fields + checkUnupdatableProductFields(product); + + Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum); + if (validateProductResponse.isRight()) { + return Either.right(validateProductResponse.right().value()); + } + + log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + + Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, "Create Product"); + if (lockResult.isRight()) { + ResponseFormat responseFormat = lockResult.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult); + + try { + Either<Product, StorageOperationStatus> createProductEither = productOperation.createProduct(product); + + if (createProductEither.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum); + componentsUtils.auditComponentAdmin(responseFormat, user, product, Constants.EMPTY_STRING, Constants.EMPTY_STRING, actionEnum, typeEnum); + return Either.right(responseFormat); + } + + log.debug("Product created successfully"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + componentsUtils.auditComponentAdmin(responseFormat, user, product, Constants.EMPTY_STRING, Constants.EMPTY_STRING, actionEnum, typeEnum); + + // //Add product to cache + Product createdProduct = createProductEither.left().value(); + // cacheManagerOperation.updateComponentInCache(createdProduct.getUniqueId(), + // createdProduct.getLastUpdateDate(), NodeTypeEnum.Product); + + return Either.left(createdProduct); + + } finally { + graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product); + } + + } + + private void checkUnupdatableProductFields(Product product) { + checkComponentFieldsForOverrideAttempt(product); + if (product.getNormalizedName() != null) { + log.info("NormalizedName cannot be defined by user. This field will be overridden by the application"); + } + } + + private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) { + + Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum); + if (validateProductFields.isRight()) { + return Either.right(validateProductFields.right().value()); + } + + if (product.getIsActive() == null) { + log.debug("no isActive value was provided, setting to default: false"); + product.setIsActive(false); + } + + product.setCreatorUserId(user.getUserId()); + + // enrich object + log.debug("enrich product with version and state"); + product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + product.setVersion(INITIAL_VERSION); + + // Generate invariant UUID - must be here and not in operation since it + // should stay constant during clone + String invariantUUID = UniqueIdBuilder.buildInvariantUUID(); + product.setInvariantUUID(invariantUUID); + + return Either.left(product); + } + + private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) { + + // To be removed in 1607 + // See below + String oldName = product.getName(); + + Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum); + if (componentNameValidation.isRight()) { + return componentNameValidation; + } + + Either<Boolean, ResponseFormat> componentNameUniquenessValidation = validateComponentNameUnique(user, product, actionEnum); + if (componentNameUniquenessValidation.isRight()) { + return componentNameUniquenessValidation; + } + + // To be removed in 1607 and replaced with generic + // validateTagsListAndRemoveDuplicates() + // See comments on the validateTagsListAndRemoveDuplicates(user, + // product, oldName, actionEnum) function + Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum); + if (tagsValidation.isRight()) { + return tagsValidation; + } + + Either<Boolean, ResponseFormat> validateIconResponse = validateIcon(user, product, actionEnum); + if (validateIconResponse.isRight()) { + return validateIconResponse; + } + + Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, product, actionEnum); + if (projectCodeValidation.isRight()) { + return projectCodeValidation; + } + Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum); + if (categoryValidation.isRight()) { + return categoryValidation; + } + + Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum); + if (contactsListValidation.isRight()) { + return contactsListValidation; + } + + Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum); + if (productFullNameValidation.isRight()) { + return productFullNameValidation; + } + + Either<Boolean, ResponseFormat> descValidation = validateDescriptionAndCleanup(user, product, actionEnum); + if (descValidation.isRight()) { + return descValidation; + } + + return Either.left(true); + } + + public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "validate Product Name Exists", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<Boolean, StorageOperationStatus> dataModelResponse = productOperation.validateComponentNameExists(productName); + + if (dataModelResponse.isLeft()) { + Map<String, Boolean> result = new HashMap<>(); + result.put("isValid", dataModelResponse.left().value()); + log.debug("validation was successfully performed."); + return Either.left(result); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value())); + + return Either.right(responseFormat); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) { + List<String> contacts = product.getContacts(); + if (!ValidationUtils.validateListNotEmpty(contacts)) { + log.debug("Contacts list cannot be empty for product {}", product.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + boolean isProductCreatorInContacts = false; + String modifierUserId = user.getUserId(); + for (String contact : contacts) { + if (contact.equals(modifierUserId)) { + log.trace("modifier userId found in product contacts"); + isProductCreatorInContacts = true; + // No need to validate for this userId - it's modifier's + continue; + } + if (!ValidationUtils.validateContactId(contact)) { + log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue()); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + User contactUser = new User(); + contactUser.setUserId(contact); + Either<User, ResponseFormat> validateUser = validateUserExists(contact, "Create Product", false); + if (validateUser.isRight()) { + log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, validateUser.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + contactUser = validateUser.left().value(); + + Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(contactUser, contactsRoles); + if (validateUserRole.isRight()) { + log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, validateUserRole.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + } + + if (!isProductCreatorInContacts) { + log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId); + contacts.add(modifierUserId); + } + + // passed - setting all contacts user ids to lowercase + List<String> tempContacts = contacts.stream().map(e -> e.toLowerCase()).collect(Collectors.toList()); + ValidationUtils.removeDuplicateFromList(tempContacts); + product.setContacts(tempContacts); + + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) { + List<CategoryDefinition> categories = product.getCategories(); + if (categories == null || categories.isEmpty()) { + log.debug("Grouping list is empty for product {}", product.getName()); + return Either.left(true); + } + Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<String, Map<String, Set<String>>>(); + // remove duplicated entries + for (CategoryDefinition cat : categories) { + String catName = cat.getName(); + if (ValidationUtils.validateStringNotEmpty(catName) == false) { + // error missing cat name + log.debug("Missing category name for product {}", product.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue()); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName); + if (catEntry == null) { + catEntry = new HashMap<String, Set<String>>(); + nonDuplicatedCategories.put(catName, catEntry); + } + List<SubCategoryDefinition> subcategories = cat.getSubcategories(); + if (subcategories == null || subcategories.isEmpty()) { + // error missing subcat for cat + log.debug("Missing sub-categories for category {} in product {}", catName, product.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + for (SubCategoryDefinition subcat : subcategories) { + String subCatName = subcat.getName(); + if (ValidationUtils.validateStringNotEmpty(subCatName) == false) { + // error missing sub cat name for cat + log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + Set<String> subcatEntry = catEntry.get(subCatName); + if (subcatEntry == null) { + subcatEntry = new HashSet<String>(); + catEntry.put(subCatName, subcatEntry); + } + List<GroupingDefinition> groupings = subcat.getGroupings(); + for (GroupingDefinition group : groupings) { + String groupName = group.getName(); + if (ValidationUtils.validateStringNotEmpty(groupName) == false) { + // error missing grouping for sub cat name and cat + log.debug("Missing or empty groupng name for sub-category {} for category {} in product {}", subCatName, catName, product.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + if (!subcatEntry.contains(groupName)) { + subcatEntry.add(groupName); + } else { + log.debug("Grouping [ {} ] already exist for category [ {} ] and subcategory [ {} ]", groupName, catName, subCatName); + } + } + } + } // for end of checking duplicated + // validate existence + Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories(); + + if (allProductCategories.isRight()) { + log.debug("No product categories {}", allProductCategories.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value()); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + boolean catExist; + // convert non-duplicated to data modeling format and update in the + // input object + List<CategoryDefinition> newCatList = new ArrayList<CategoryDefinition>(); + + // over all categories from request + for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) { + catExist = false; + CategoryDefinition categoryDefinition = null; + // over all categories from Titan + List<CategoryDefinition> categoriesList = allProductCategories.left().value(); + if (categoriesList != null) { + for (CategoryDefinition catInDb : categoriesList) { + if (entry.getKey().equals(catInDb.getName())) { + catExist = true; + boolean subcatExist; + // copy data + categoryDefinition = new CategoryDefinition(catInDb); + SubCategoryDefinition subCategory = null; + + Map<String, Set<String>> subcats = entry.getValue(); + for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) { + subcatExist = false; + List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories(); + if (subcategoriesList != null) { + for (SubCategoryDefinition subcatInDb : subcategoriesList) { + if (subcatInDb.getName().equals(subcat.getKey())) { + // copy data + subCategory = new SubCategoryDefinition(subcatInDb); + subcatExist = true; + Set<String> grouping = subcat.getValue(); + boolean groupExist; + GroupingDefinition groupingDefinition = null; + for (String group : grouping) { + groupExist = false; + List<GroupingDefinition> groupings = subcatInDb.getGroupings(); + if (groupings != null) { + for (GroupingDefinition groupInDb : groupings) { + if (groupInDb.getName().equals(group)) { + groupExist = true; + groupingDefinition = new GroupingDefinition(groupInDb); + } + } + } + if (!groupExist) { + // error grouping isn't defined + // in Titan + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + subCategory.addGrouping(groupingDefinition); + } + } + } + } + if (!subcatExist) { + // error sub category isn't defined in Titan + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey()); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + categoryDefinition.addSubCategory(subCategory); + } + } + } + } + if (!catExist) { + // error category isn't defined in Titan + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey()); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + newCatList.add(categoryDefinition); + } + product.setCategories(newCatList); + return Either.left(true); + } + + public Either<Product, ResponseFormat> getProduct(String productId, User user) { + String ecompErrorContext = "Get product"; + Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext); + if (validateEmptyResult.isRight()) { + return Either.right(validateEmptyResult.right().value()); + } + + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + + Either<Product, StorageOperationStatus> storageStatus = productOperation.getComponent(productId, false); + + if (storageStatus.isRight()) { + log.debug("failed to get resource by id {}", productId); + if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + // TODO check error + return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue())); + } else { + return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), "")); + } + } + return Either.left(storageStatus.left().value()); + } + + public Either<Product, ResponseFormat> deleteProduct(String productId, User user) { + String ecompErrorContext = "Delete product"; + Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext); + if (validateEmptyResult.isRight()) { + return Either.right(validateEmptyResult.right().value()); + } + + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + + Either<Product, StorageOperationStatus> storageStatus = productOperation.deleteProduct(productId, false); + + if (storageStatus.isRight()) { + log.debug("failed to delete resource by id {}", productId); + return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), "")); + } + return Either.left(storageStatus.left().value()); + } + + private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) { + String fullName = product.getFullName(); + if (!ValidationUtils.validateStringNotEmpty(fullName)) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME); + componentsUtils.auditComponentAdmin(errorResponse, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(errorResponse); + } + + fullName = ValidationUtils.removeNoneUtf8Chars(fullName); + fullName = ValidationUtils.removeHtmlTags(fullName); + fullName = ValidationUtils.normaliseWhitespace(fullName); + fullName = ValidationUtils.stripOctets(fullName); + + if (!ValidationUtils.validateProductFullNameLength(fullName)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + if (!ValidationUtils.validateIsEnglish(fullName)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + product.setFullName(fullName); + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) { + String name = product.getName(); + if (!ValidationUtils.validateStringNotEmpty(name)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + // Product name is required to have same validation and normalization as + // category + if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name); + + if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + + product.setName(normalizedName4Display); + String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display); + product.setNormalizedName(normalizedName4Uniqueness); + + return Either.left(true); + } + + // This is a workaround for a current tag--->product name behaviour, which + // will be changed in 1607. + // It was agreed with Ella on 23/2/16 that the tag validation of product + // will be made against the old product name (before normalization), + // and in 1607 US will be defined where UI will no longer pass tag of + // component name, and BE will add it by itself after all needed + // normalizations. + private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) { + List<String> tagsList = product.getTags(); + + Either<Boolean, ResponseFormat> validateTags = validateComponentTags(tagsList, oldProductName, ComponentTypeEnum.PRODUCT); + if (validateTags.isRight()) { + ResponseFormat responseFormat = validateTags.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, product, "", "", actionEnum, ComponentTypeEnum.PRODUCT); + return Either.right(responseFormat); + } + ValidationUtils.removeDuplicateFromList(tagsList); + return Either.left(true); + } + + @Override + public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) { + + } + + public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) { + ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT; + Either<User, ResponseFormat> eitherCreator = validateUser(user, "Update Product", updatedProduct, null, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + // validate user role + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, updatedProduct, updateRoles, null, null); + if (validateRes.isRight()) { + return Either.right(validateRes.right().value()); + } + + if (updatedProduct == null) { + log.debug("Invalid product json. Check product servlet log for updateProduct entry params"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + return Either.right(responseFormat); + } + + Either<Product, StorageOperationStatus> storageStatus = productOperation.getComponent(productId, false); + if (storageStatus.isRight()) { + if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase())); + } + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), "")); + } + + Product currentProduct = storageStatus.left().value(); + + if (!ComponentValidationUtils.canWorkOnComponent(productId, productOperation, user.getUserId())) { + log.info("Restricted operation for user {} on product {}", user.getUserId(), currentProduct.getCreatorUserId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct); + if (validationRsponse.isRight()) { + log.info("product update metadata: validations field."); + return validationRsponse; + } + + Product productToUpdate = validationRsponse.left().value(); + // lock resource + Either<Boolean, ResponseFormat> lockResult = lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata"); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either<Product, StorageOperationStatus> updateResponse = productOperation.updateComponent(productToUpdate, true); + if (updateResponse.isRight()) { + productOperation.rollback(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Update Product Metadata"); + log.debug("failed to update product {}", productToUpdate.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + productOperation.commit(); + return Either.left(updateResponse.left().value()); + } finally { + graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product); + } + } + + private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) { + + boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion()); + Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateFullName(user, currentProduct, updatedProduct); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateCategory(user, currentProduct, updatedProduct); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateContactList(user, currentProduct, updatedProduct); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateTags(user, currentProduct, updatedProduct); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + if (updatedProduct.getIsActive() != null) { + currentProduct.setIsActive(updatedProduct.getIsActive()); + } + + response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + String currentInvariantUuid = currentProduct.getInvariantUUID(); + String updatedInvariantUuid = updatedProduct.getInvariantUUID(); + + if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) { + log.warn("Product invariant UUID is automatically set and cannot be updated"); + updatedProduct.setInvariantUUID(currentInvariantUuid); + } + return Either.left(currentProduct); + + } + + private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) { + String updatedProductName = updatedProduct.getName(); + String tags = ""; + String currentProductName = currentProduct.getName(); + if (updatedProductName != null) { + Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null); + if (validatProductNameResponse.isRight()) { + ResponseFormat errorRespons = validatProductNameResponse.right().value(); + return Either.right(errorRespons); + } + updatedProductName = updatedProduct.getName(); + if (!currentProductName.equals(updatedProductName)) { + Either<Boolean, ResponseFormat> productNameUniquenessValidation = validateComponentNameUnique(user, updatedProduct, null); + if (productNameUniquenessValidation.isRight()) { + return productNameUniquenessValidation; + } + currentProduct.setName(updatedProductName); + tags = updatedProductName; + updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName); + currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName)); + List<String> updatedTags = updatedProduct.getTags(); + // As discussed with Ella currently (1604) we are not removing + // the old name from tags. + if (updatedTags == null) { + updatedTags = currentProduct.getTags(); + } + updatedTags.add(tags); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) { + String updatedProductName = updatedProduct.getFullName(); + String currentProductName = currentProduct.getFullName(); + if (updatedProductName != null && !currentProductName.equals(updatedProductName)) { + Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null); + if (validatProductNameResponse.isRight()) { + ResponseFormat errorRespons = validatProductNameResponse.right().value(); + return Either.right(errorRespons); + } + currentProduct.setFullName(updatedProduct.getFullName()); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) { + List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories(); + List<CategoryDefinition> categoryCurrent = currentProduct.getCategories(); + + Either<Boolean, ResponseFormat> validatCategoryResponse = validateGrouping(user, updatedProduct, null); + if (validatCategoryResponse.isRight()) { + ResponseFormat errorResponse = validatCategoryResponse.right().value(); + return Either.right(errorResponse); + } + + categoryUpdated = updatedProduct.getCategories(); + if (categoryUpdated != null) { + currentProduct.setCategories(categoryUpdated); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) { + List<String> updatedContacts = updatedProduct.getContacts(); + List<String> currentContacts = currentProduct.getContacts(); + if (updatedContacts != null) { + if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) { + Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null); + if (validatResponse.isRight()) { + ResponseFormat errorRespons = validatResponse.right().value(); + return Either.right(errorRespons); + } + currentProduct.setContacts(updatedProduct.getContacts()); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) { + List<String> tagsUpdated = updatedProduct.getTags(); + List<String> tagsCurrent = currentProduct.getTags(); + if (tagsUpdated != null) { + if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) { + Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null); + if (validatResponse.isRight()) { + ResponseFormat errorRespons = validatResponse.right().value(); + return Either.right(errorRespons); + } + currentProduct.setTags(updatedProduct.getTags()); + } + } + return Either.left(true); + } + + @Override + public Either<List<String>, ResponseFormat> deleteMarkedComponents() { + // markAsDeleted isnt implemented yet + return Either.left(new ArrayList<>()); + } + + @Override + protected boolean validateTagPattern(String tag) { + return ValidationUtils.validateCategoryDisplayNameFormat(tag); + } + + public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Service By Name And Version", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<Product, StorageOperationStatus> storageStatus = productOperation.getProductByNameAndVersion(productName, productVersion, false); + if (storageStatus.isRight()) { + log.debug("failed to get service by name {} and version {}", productName, productVersion); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName)); + } + Product product = storageStatus.left().value(); + return Either.left(product); + } + + @Override + public ComponentInstanceBusinessLogic getComponentInstanceBL() { + return productComponentInstanceBusinessLogic; + } + + @Override + public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, ComponentTypeEnum componentTypeEnum, String userId, String searchText) { + return null; + } + + public ICacheMangerOperation getCacheManagerOperation() { + return cacheManagerOperation; + } + + public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) { + this.cacheManagerOperation = cacheManagerOperation; + } + + public void setProductOperation(ProductOperation productOperation) { + this.productOperation = productOperation; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ProductComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ProductComponentInstanceBusinessLogic.java new file mode 100644 index 0000000000..46188012d8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ProductComponentInstanceBusinessLogic.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("productComponentInstanceBusinessLogic") +public class ProductComponentInstanceBusinessLogic extends ComponentInstanceBusinessLogic { + + @Override + protected Either<Boolean, ResponseFormat> validateAllowedToContainCompInstances(org.openecomp.sdc.be.model.Component containerComponent) { + return Either.left(true); + } + + @Override + protected NodeTypeEnum getNodeTypeOfComponentInstanceOrigin() { + // TODO Pavel this might be also a resource? + return NodeTypeEnum.Service; + } + + @Override + protected ComponentOperation getContainerComponentOperation() { + return productOperation; + } + + @Override + protected ComponentOperation getCompInstOriginComponentOperation() { + return serviceOperation; + } + + @Override + protected ComponentTypeEnum getComponentTypeOfComponentInstance() { + return ComponentTypeEnum.SERVICE_INSTANCE; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java new file mode 100644 index 0000000000..1e6b1c1d82 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java @@ -0,0 +1,391 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.ServletContext; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; +import org.openecomp.sdc.be.resources.data.EntryData; +import org.openecomp.sdc.be.resources.data.PropertyData; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.WebApplicationContext; + +import fj.data.Either; + +@Component("propertyBusinessLogic") +public class PropertyBusinessLogic extends BaseBusinessLogic { + + private static final String CREATE_PROPERTY = "CreateProperty"; + + private static Logger log = LoggerFactory.getLogger(PropertyBusinessLogic.class.getName()); + + @javax.annotation.Resource + private IResourceOperation resourceOperation = null; + + @javax.annotation.Resource + private PropertyOperation propertyOperation = null; + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + protected static IElementOperation getElementDao(Class<IElementOperation> class1, ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + + return webApplicationContext.getBean(class1); + } + + public Either<Map<String, DataTypeDefinition>, ResponseFormat> getAllDataTypes() { + Either<Map<String, DataTypeDefinition>, ResponseFormat> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache); + return eitherAllDataTypes; + } + + /** + * Create new property on resource in graph + * + * @param resourceId + * @param propertyName + * @param newPropertyDefinition + * @param userId + * @return Either<PropertyDefinition, ActionStatus> + */ + public Either<EntryData<String, PropertyDefinition>, ResponseFormat> createProperty(String resourceId, String propertyName, PropertyDefinition newPropertyDefinition, String userId) { + + Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null; + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Property", false); + if (resp.isRight()) { + result = Either.right(resp.right().value()); + return result; + } + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + log.info("Failed to lock component {}. Error - {}", resourceId, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return result; + } + Resource resource = status.left().value(); + + // verify that resource is checked-out and the user is the last + // updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return result; + } + + // verify property not exist in resource + List<PropertyDefinition> resourceProperties = resource.getProperties(); + + if (resourceProperties != null) { + if (propertyOperation.isPropertyExist(resourceProperties, resourceId, propertyName)) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, "")); + return result; + } + } + + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); + if (allDataTypes.isRight()) { + result = Either.right(allDataTypes.right().value()); + return result; + } + + Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); + + // validate property default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, dataTypes); + if (defaultValuesValidation.isRight()) { + result = Either.right(defaultValuesValidation.right().value()); + return result; + } + // convert property + ToscaPropertyType type = getType(newPropertyDefinition.getType()); + if (type != null) { + PropertyValueConverter converter = type.getConverter(); + // get inner type + String innerType = null; + if (newPropertyDefinition != null) { + SchemaDefinition schema = newPropertyDefinition.getSchema(); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (prop != null) { + innerType = prop.getType(); + } + } + String convertedValue = null; + if (newPropertyDefinition.getDefaultValue() != null) { + convertedValue = converter.convert(newPropertyDefinition.getDefaultValue(), innerType, allDataTypes.left().value()); + newPropertyDefinition.setDefaultValue(convertedValue); + } + } + } + + // add the new property to resource on graph + // need to get StorageOpaerationStatus and convert to ActionStatus + // from componentsUtils + Either<PropertyData, StorageOperationStatus> either = propertyOperation.addProperty(propertyName, newPropertyDefinition, resourceId); + if (either.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); + return result; + } + + PropertyDefinition createdPropertyDefinition = propertyOperation.convertPropertyDataToPropertyDefinition(either.left().value(), propertyName, resourceId); + EntryData<String, PropertyDefinition> property = new EntryData<String, PropertyDefinition>(propertyName, createdPropertyDefinition); + result = Either.left(property); + return result; + + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + + } + + /** + * Get property of resource + * + * @param resourceId + * @param propertyId + * @param userId + * TODO + * @return + */ + public Either<Entry<String, PropertyDefinition>, ResponseFormat> getProperty(String resourceId, String propertyId, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "create Component Instance", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Resource resource = status.left().value(); + + // verify property exist in resource + List<PropertyDefinition> properties = resource.getProperties(); + if (properties == null) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, "")); + } + for (PropertyDefinition property : properties) { + // esofer - check also that the property belongs to the current + // resource + if (property.getUniqueId().equals(propertyId) && property.getParentUniqueId().equals(resourceId)) { + Map<String, PropertyDefinition> propMap = new HashMap<>(); + propMap.put(property.getName(), property); + return Either.left(propMap.entrySet().iterator().next()); + } + } + return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, "")); + } + + /** + * delete property of resource from graph + * + * @param resourceId + * @param propertyId + * @param userId + * @return + */ + public Either<EntryData<String, PropertyDefinition>, ResponseFormat> deleteProperty(String resourceId, String propertyId, String userId) { + + Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null; + + Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Property", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return result; + } + Resource resource = status.left().value(); + + // verify that resource is checked-out and the user is the last + // updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return result; + } + + // verify property exist in resource + Either<Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = getProperty(resourceId, propertyId, userId); + if (statusGetProperty.isRight()) { + result = Either.right(statusGetProperty.right().value()); + return result; + } + String propertyName = statusGetProperty.left().value().getKey(); + + // delete property of resource from graph + // TODO: need to get StorageOperationStatus + Either<PropertyData, StorageOperationStatus> either = propertyOperation.deleteProperty(propertyId); + // Either<PropertyData, StorageOperationStatus> either = + // propertyOperation.deletePropertyFromGraph(propertyId); + if (either.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); + return result; + } + // propertyOperation.getTitanGenericDao().commit(); + PropertyDefinition createdPropertyDefinition = propertyOperation.convertPropertyDataToPropertyDefinition(either.left().value(), propertyName, resourceId); + EntryData<String, PropertyDefinition> property = new EntryData<String, PropertyDefinition>(propertyName, createdPropertyDefinition); + result = Either.left(property); + return result; + + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + } + + /** + * update property + * + * @param resourceId + * @param propertyId + * @param newPropertyDefinition + * @param userId + * @return + */ + public Either<EntryData<String, PropertyDefinition>, ResponseFormat> updateProperty(String resourceId, String propertyId, PropertyDefinition newPropertyDefinition, String userId) { + + Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null; + + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Resource resource = status.left().value(); + + // verify that resource is checked-out and the user is the last updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + + // verify property exist in resource + Either<Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = getProperty(resourceId, propertyId, userId); + if (statusGetProperty.isRight()) { + result = Either.right(statusGetProperty.right().value()); + return result; + } + String propertyName = statusGetProperty.left().value().getKey(); + + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); + if (allDataTypes.isRight()) { + result = Either.right(allDataTypes.right().value()); + return result; + } + Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); + // validate property default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, dataTypes); + if (defaultValuesValidation.isRight()) { + result = Either.right(defaultValuesValidation.right().value()); + return result; + } + + // add the new property to resource on graph + // TODO: convert TitanOperationStatus to Storgae... + Either<PropertyData, StorageOperationStatus> either = propertyOperation.updateProperty(propertyId, newPropertyDefinition, dataTypes); + // Either<PropertyData, StorageOperationStatus> either = + // propertyOperation.updatePropertyFromGraph(propertyId, + // newPropertyDefinition); + if (either.isRight()) { + log.debug("Problem while updating property with id {}. Reason - {}", propertyId, either.right().value()); + result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); + return result; + // return Either.right(ActionStatus.GENERAL_ERROR); + } + + PropertyDefinition createdPropertyDefinition = propertyOperation.convertPropertyDataToPropertyDefinition(either.left().value(), propertyName, resourceId); + EntryData<String, PropertyDefinition> property = new EntryData<String, PropertyDefinition>(propertyName, createdPropertyDefinition); + result = Either.left(property); + return result; + + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementsBusinessLogic.java new file mode 100644 index 0000000000..f8dde98010 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementsBusinessLogic.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("requirementsBusinessLogic") +public class RequirementsBusinessLogic { + private static Logger log = LoggerFactory.getLogger(RequirementsBusinessLogic.class.getName()); + + @javax.annotation.Resource + private ComponentsUtils componentsUtils; + + @javax.annotation.Resource + private ResourceBusinessLogic resourceBusinessLogic; + + @javax.annotation.Resource + private IResourceOperation resourceOperation; + + public Either<RequirementDefinition, ResponseFormat> updateRequirement(String resourceId, String requirementId, RequirementDefinition requirementDefinition, String userId) { + + // Get the resource from DB + Either<Resource, StorageOperationStatus> status = getResource(resourceId); + if (status.isRight()) { + log.debug("Couldn't get resource {} from DB", resourceId); + return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(status.right().value()), "")); + } + Resource resource = status.left().value(); + if (resource == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeResourceMissingError, "Requirement Business Logic", resourceId); + BeEcompErrorManager.getInstance().logBeComponentMissingError("Requirement Business Logic", ComponentTypeEnum.RESOURCE.getValue(), resourceId); + log.debug("Couldn't get resource {} from DB", resourceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + // verify that resource is checked-out and the user is the last updater + if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + // TODO + return null; + } + + private Either<Resource, StorageOperationStatus> getResource(final String resourceId) { + + log.debug("Get resource with id {}", resourceId); + Either<Resource, StorageOperationStatus> status = resourceOperation.getResource(resourceId); + if (status.isRight()) { + log.debug("Resource with id {} was not found", resourceId); + return Either.right(status.right().value()); + } + + Resource resource = status.left().value(); + if (resource == null) { + log.debug("General Error while get resource with id {}", resourceId); + return Either.right(StorageOperationStatus.GENERAL_ERROR); + } + return Either.left(resource); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java new file mode 100644 index 0000000000..ddc03e14e8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java @@ -0,0 +1,5475 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.servlet.ServletContext; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic.ArtifactOperation; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction.LifecycleChanceActionEnum; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; +import org.openecomp.sdc.be.datamodel.utils.ArtifactUtils; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.info.ArtifactTemplateInfo; +import org.openecomp.sdc.be.info.MergedArtifactInfo; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.CapabilityTypeDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GetInputValueInfo; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.GroupProperty; +import org.openecomp.sdc.be.model.GroupTypeDefinition; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.ParsedToscaYamlInfo; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.UploadCapInfo; +import org.openecomp.sdc.be.model.UploadComponentInstanceInfo; +import org.openecomp.sdc.be.model.UploadPropInfo; +import org.openecomp.sdc.be.model.UploadReqInfo; +import org.openecomp.sdc.be.model.UploadResourceInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.model.heat.HeatParameterType; +import org.openecomp.sdc.be.model.operations.api.IArtifactOperation; +import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation; +import org.openecomp.sdc.be.model.operations.api.ICapabilityTypeOperation; +import org.openecomp.sdc.be.model.operations.api.IComponentInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IHeatParametersOperation; +import org.openecomp.sdc.be.model.operations.api.IInterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.IPropertyOperation; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.CapabilityInstanceOperation; +import org.openecomp.sdc.be.model.operations.impl.CsarOperation; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.GroupOperation; +import org.openecomp.sdc.be.model.operations.impl.InputsOperation; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.resources.data.ResourceMetadataData; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.servlets.RepresentationUtils; +import org.openecomp.sdc.be.user.IUserBusinessLogic; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.be.utils.CommonBeUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.kpi.api.ASDCKpiApi; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.context.WebApplicationContext; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.representer.Representer; +import org.yaml.snakeyaml.resolver.Resolver; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import fj.data.Either; + +@org.springframework.stereotype.Component("resourceBusinessLogic") +public class ResourceBusinessLogic extends ComponentBusinessLogic { + + private static final String PLACE_HOLDER_RESOURCE_TYPES = "validForResourceTypes"; + public static final String INITIAL_VERSION = "0.1"; + + Pattern STR_REPLACE_PATTERN = Pattern.compile("^[ ]*\\{[ ]*" + "str_replace" + "="); + Pattern TOKEN_PATTERN = Pattern.compile("[ ]*\\{[ ]*" + "token" + "="); + Pattern GET_PROPERTY_PATTERN = Pattern.compile("[ ]*\\{[ ]*" + "get_property" + "="); + Pattern CONCAT_PATTERN = Pattern.compile("[ ]*\\{[ ]*" + "concat" + "="); + + private static Logger log = LoggerFactory.getLogger(ResourceBusinessLogic.class.getName()); + + public ResourceBusinessLogic() { + log.debug("ResourceBusinessLogic started"); + } + + @Autowired + private ICapabilityTypeOperation capabilityTypeOperation = null; + + @Autowired + private IInterfaceLifecycleOperation interfaceTypeOperation = null; + + @Autowired + private IComponentInstanceOperation componentInstanceOperation; + + @Autowired + private LifecycleBusinessLogic lifecycleBusinessLogic; + + @Autowired + private IPropertyOperation propertyOperation; + + @Autowired + private CsarOperation csarOperation; + + @Autowired + private VFComponentInstanceBusinessLogic vfComponentInstanceBusinessLogic; + + @Autowired + private ResourceImportManager resourceImportManager; + + @Autowired + private GroupBusinessLogic groupBusinessLogic; + @Autowired + private InputsBusinessLogic inputsBusinessLogic; + + @javax.annotation.Resource + private InputsOperation inputOperation; + + @Autowired + private GroupOperation groupOperation; + + @Autowired + private IHeatParametersOperation heatParametersOperation; + + @Autowired + private IArtifactOperation artifactOperation; + + @Autowired + private CapabilityInstanceOperation capabilityInstanceOperation; + + @Autowired + private CompositionBusinessLogic compositionBusinessLogic; + + @Autowired + private ICacheMangerOperation cacheManagerOperation; + + private Gson gson = new Gson(); + + public CsarOperation getCsarOperation() { + return csarOperation; + } + + public void setCsarOperation(CsarOperation csarOperation) { + this.csarOperation = csarOperation; + } + + public IResourceOperation getResourceOperation() { + return this.resourceOperation; + } + + public void setResourceOperation(ResourceOperation resourceOperation) { + this.resourceOperation = resourceOperation; + } + + public LifecycleBusinessLogic getLifecycleBusinessLogic() { + return lifecycleBusinessLogic; + } + + public void setLifecycleManager(LifecycleBusinessLogic lifecycleBusinessLogic) { + this.lifecycleBusinessLogic = lifecycleBusinessLogic; + } + + public IElementOperation getElementDao() { + return elementDao; + } + + public void setElementDao(IElementOperation elementDao) { + this.elementDao = elementDao; + } + + public IUserBusinessLogic getUserAdmin() { + return this.userAdmin; + } + + public void setUserAdmin(UserBusinessLogic userAdmin) { + this.userAdmin = userAdmin; + } + + public ComponentsUtils getComponentsUtils() { + return this.componentsUtils; + } + + public void setComponentsUtils(ComponentsUtils componentsUtils) { + this.componentsUtils = componentsUtils; + } + + public ArtifactsBusinessLogic getArtifactsManager() { + return artifactsBusinessLogic; + } + + public void setArtifactsManager(ArtifactsBusinessLogic artifactsManager) { + this.artifactsBusinessLogic = artifactsManager; + } + + public void setPropertyOperation(IPropertyOperation propertyOperation) { + this.propertyOperation = propertyOperation; + } + + public ApplicationDataTypeCache getApplicationDataTypeCache() { + return applicationDataTypeCache; + } + + public void setApplicationDataTypeCache(ApplicationDataTypeCache applicationDataTypeCache) { + this.applicationDataTypeCache = applicationDataTypeCache; + } + + /** + * the method returns a list of all the resources that are certified, the returned resources are only abstract or only none abstract according to the given param + * + * @param getAbstract + * @param userId + * TODO + * @return + */ + public Either<List<Resource>, ResponseFormat> getAllCertifiedResources(boolean getAbstract, HighestFilterEnum highestFilter, String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get All Certified Resources", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + IResourceOperation dataModel = getResourceOperation(); + Boolean isHighest = null; + switch (highestFilter) { + case ALL: + break; + case HIGHEST_ONLY: + isHighest = true; + break; + case NON_HIGHEST_ONLY: + isHighest = false; + break; + default: + break; + } + + Either<List<Resource>, StorageOperationStatus> dataModelResponse = dataModel.getAllCertifiedResources(getAbstract, isHighest); + + if (dataModelResponse.isLeft()) { + log.debug("Retrived Resource successfully."); + return Either.left(dataModelResponse.left().value()); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value())); + + return Either.right(responseFormat); + } + + public Either<Map<String, Boolean>, ResponseFormat> validateResourceNameExists(String resourceName, ResourceTypeEnum resourceTypeEnum, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "validate Resource Name Exists", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + IResourceOperation dataModel = getResourceOperation(); + + Either<Boolean, StorageOperationStatus> dataModelResponse = dataModel.validateResourceNameExists(resourceName, resourceTypeEnum); + + if (dataModelResponse.isLeft()) { + Map<String, Boolean> result = new HashMap<>(); + result.put("isValid", dataModelResponse.left().value()); + log.debug("validation was successfully performed."); + return Either.left(result); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value())); + + return Either.right(responseFormat); + } + + public Either<Resource, ResponseFormat> createResource(Resource resource, User user, Map<String, byte[]> csarUIPayload, String payloadName) { + Either<Resource, ResponseFormat> createResourceResponse = validateResourceBeforeCreate(resource, user, false); + if (createResourceResponse.isRight()) { + return createResourceResponse; + } + + // Creating resource either by DAO or from CSAR + String csarUUID = null; + if (payloadName == null) { + csarUUID = resource.getCsarUUID(); + } else { + csarUUID = payloadName; + } + if (csarUUID != null && !csarUUID.isEmpty()) { + // check if VF with the same Csar UUID or with he same name already + // exists + Either<List<ResourceMetadataData>, StorageOperationStatus> validateCsarUuidUniquenessRes = resourceOperation.validateCsarUuidUniqueness(csarUUID); + if (validateCsarUuidUniquenessRes.isRight()) { + log.debug("Failed to validate uniqueness of CsarUUID {} for resource", csarUUID, resource.getSystemName()); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(validateCsarUuidUniquenessRes.right().value()))); + } + + List<ResourceMetadataData> existingResourceRes = validateCsarUuidUniquenessRes.left().value(); + if (existingResourceRes != null && existingResourceRes.size() > 0) { + log.debug("Failed to create resource {}, csarUUID {} already exist for a different VF {}", resource.getSystemName(), csarUUID, existingResourceRes.get(0).getMetadataDataDefinition().getName()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.VSP_ALREADY_EXISTS, csarUUID, existingResourceRes.get(0).getMetadataDataDefinition().getName()); + componentsUtils.auditResource(errorResponse, user, resource, "", "", AuditingActionEnum.CREATE_RESOURCE, null); + return Either.right(errorResponse); + } + + log.debug("CsarUUID is {} - going to create resource from CSAR", csarUUID); + createResourceResponse = createResourceFromCsar(resource, user, AuditingActionEnum.CREATE_RESOURCE, false, Either.left(csarUIPayload), csarUUID); + return createResourceResponse; + } + + return createResourceByDao(resource, user, AuditingActionEnum.CREATE_RESOURCE, false); + } + + public Either<Resource, ResponseFormat> validateAndUpdateResourceFromCsar(Resource resource, User user, Map<String, byte[]> csarUIPayload, String payloadName, String resourceUniqueId) { + Either<Resource, ResponseFormat> updateResourceResponse = null; + Either<Resource, ResponseFormat> validateResourceResponse = null; + Wrapper<ResponseFormat> responseWrapper = new Wrapper<ResponseFormat>(); + String csarUUID = null; + String csarVersion = null; + if (payloadName == null) { + csarUUID = resource.getCsarUUID(); + csarVersion = resource.getCsarVersion(); + } else { + csarUUID = payloadName; + } + if (csarUUID != null && !csarUUID.isEmpty()) { + Resource oldResource = getResourceByUniqueId(responseWrapper, resourceUniqueId); + if (responseWrapper.isEmpty()) { + validateCsarUuidMatching(responseWrapper, oldResource, resource, csarUUID, resourceUniqueId, user); + } + if (responseWrapper.isEmpty()) { + validateCsarIsNotAlreadyUsed(responseWrapper, oldResource, resource, csarUUID, user); + } + if (responseWrapper.isEmpty()) { + if (oldResource != null && ValidationUtils.hasBeenCertified(oldResource.getVersion())) { + overrideImmutableMetadata(oldResource, resource); + } + validateResourceResponse = validateResourceBeforeCreate(resource, user, false); + if (validateResourceResponse.isRight()) { + responseWrapper.setInnerElement(validateResourceResponse.right().value()); + } + } + if (responseWrapper.isEmpty()) { + String oldCsarVersion = oldResource.getCsarVersion(); + log.debug("CsarUUID is {} - going to update resource with UniqueId {} from CSAR", csarUUID, resourceUniqueId); + // (on boarding flow): If the update includes same csarUUID and + // same csarVersion as already in the VF - no need to import the + // csar (do only metadata changes if there are). + if (csarVersion != null && oldCsarVersion != null && oldCsarVersion.equals(csarVersion)) { + updateResourceResponse = updateResourceMetadata(resourceUniqueId, resource, oldResource, user, false); + } else { + updateResourceResponse = updateResourceFromCsar(oldResource, resource, user, AuditingActionEnum.UPDATE_RESOURCE_METADATA, false, Either.left(csarUIPayload), csarUUID); + } + } + } else { + log.debug("Failed to update resource {}, csarUUID or payload name is missing", resource.getSystemName()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_CSAR_UUID, resource.getName()); + componentsUtils.auditResource(errorResponse, user, resource, "", "", AuditingActionEnum.CREATE_RESOURCE, null); + responseWrapper.setInnerElement(errorResponse); + } + if (responseWrapper.isEmpty()) { + return updateResourceResponse; + } + return Either.right(responseWrapper.getInnerElement()); + } + + private void validateCsarIsNotAlreadyUsed(Wrapper<ResponseFormat> responseWrapper, Resource oldResource, Resource resource, String csarUUID, User user) { + // (on boarding flow): If the update includes a csarUUID: verify this + // csarUUID is not in use by another VF, If it is - use same error as + // above: + // "Error: The VSP with UUID %1 was already imported for VF %2. Please + // select another or update the existing VF." %1 - csarUUID, %2 - VF + // name + Either<Resource, StorageOperationStatus> resourceLinkedToCsarRes = resourceOperation.getLatestResourceByCsarOrName(csarUUID, resource.getSystemName()); + if (resourceLinkedToCsarRes.isRight()) { + if (!StorageOperationStatus.NOT_FOUND.equals(resourceLinkedToCsarRes.right().value())) { + log.debug("Failed to find previous resource by CSAR {} and system name {}", csarUUID, resource.getSystemName()); + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resourceLinkedToCsarRes.right().value()))); + } + } else if (!resourceLinkedToCsarRes.left().value().getUniqueId().equals(oldResource.getUniqueId()) && !resourceLinkedToCsarRes.left().value().getName().equals(oldResource.getName())) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.VSP_ALREADY_EXISTS, csarUUID, resourceLinkedToCsarRes.left().value().getName()); + componentsUtils.auditResource(errorResponse, user, resource, "", "", AuditingActionEnum.UPDATE_RESOURCE_METADATA, null); + responseWrapper.setInnerElement(errorResponse); + } + } + + private void validateCsarUuidMatching(Wrapper<ResponseFormat> responseWrapper, Resource resource, Resource oldResource, String csarUUID, String resourceUniqueId, User user) { + // (on boarding flow): If the update includes csarUUID which is + // different from the csarUUID of the VF - fail with + // error: "Error: Resource %1 cannot be updated using since it is linked + // to a different VSP" %1 - VF name + String oldCsarUUID = oldResource.getCsarUUID(); + if (oldCsarUUID != null && !oldCsarUUID.isEmpty() && !csarUUID.equals(oldCsarUUID)) { + log.debug("Failed to update resource with UniqueId {} using Csar {}, since the resource is linked to a different VSP {}", resourceUniqueId, csarUUID, oldCsarUUID); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_LINKED_TO_DIFFERENT_VSP, resource.getName(), csarUUID, oldCsarUUID); + componentsUtils.auditResource(errorResponse, user, resource, "", "", AuditingActionEnum.UPDATE_RESOURCE_METADATA, null); + responseWrapper.setInnerElement(errorResponse); + } + } + + private Resource getResourceByUniqueId(Wrapper<ResponseFormat> responseWrapper, String resourceUniqueId) { + Either<Resource, StorageOperationStatus> oldResourceRes = resourceOperation.getResource(resourceUniqueId); + if (oldResourceRes.isRight()) { + log.debug("Failed to find previous resource by UniqueId {}, status: {}", resourceUniqueId, oldResourceRes.right().value()); + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(oldResourceRes.right().value()))); + return null; + } + return oldResourceRes.left().value(); + } + + private void overrideImmutableMetadata(Resource oldRresource, Resource resource) { + resource.setName(oldRresource.getName()); + resource.setIcon(oldRresource.getIcon()); + resource.setTags(oldRresource.getTags()); + resource.setVendorName(oldRresource.getVendorName()); + resource.setCategories(oldRresource.getCategories()); + resource.setDerivedFrom(oldRresource.getDerivedFrom()); + } + + private Either<Resource, ResponseFormat> updateResourceFromCsar(Resource oldRresource, Resource newRresource, User user, AuditingActionEnum updateResource, boolean inTransaction, Either<Map<String, byte[]>, StorageOperationStatus> csarUIPayload, + String csarUUID) { + + // check state + if (LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.equals(oldRresource.getLifecycleState())) { + if (!oldRresource.getLastUpdaterUserId().equals(user.getUserId())) { + log.debug("Current user is not last updater, last updater userId: {}, current user userId: {}", oldRresource.getLastUpdaterUserId(), user.getUserId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + } + String lockedResourceId = oldRresource.getUniqueId(); + List<ArtifactDefinition> createdArtifacts = new ArrayList<ArtifactDefinition>(); + + Either<Map<String, byte[]>, StorageOperationStatus> csar = null; + if (csarUIPayload != null && csarUIPayload.left() != null && csarUIPayload.left().value() != null) { + csar = csarUIPayload; + } else { + csar = csarOperation.getCsar(csarUUID, user); + } + if (csar.isRight()) { + log.debug("Failed to get csar for casrUUID{} ", csarUUID); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(csar.right().value()))); + } + + Either<ImmutablePair<String, String>, ResponseFormat> toscaYamlCsarStatus = validateAndParseCsar(newRresource, user, csarUUID, csar); + if (toscaYamlCsarStatus.isRight()) { + return Either.right(toscaYamlCsarStatus.right().value()); + } + Either<String, ResponseFormat> checksum = CsarValidationUtils.getToscaYamlChecksum(csar.left().value(), csarUUID, componentsUtils); + if (checksum.isRight()) { + log.debug("Failed to calculate checksum for casrUUID{} error {} ", csarUUID, checksum.right().value()); + return Either.right(checksum.right().value()); + } + boolean isUpdateYaml = true; + if (checksum.left().value().equals(oldRresource.getComponentMetadataDefinition().getMetadataDataDefinition().getImportedToscaChecksum())) { + log.debug("The checksums are equals for csarUUID {}, existing checsum is {}, new one is {} ", csarUUID, oldRresource.getComponentMetadataDefinition().getMetadataDataDefinition().getImportedToscaChecksum(), checksum.left().value()); + if (oldRresource.getLifecycleState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) + isUpdateYaml = false; + } else { + oldRresource.getComponentMetadataDefinition().getMetadataDataDefinition().setImportedToscaChecksum(checksum.left().value()); + } + + Either<Boolean, ResponseFormat> lockResult = lockComponent(lockedResourceId, oldRresource, "update Resource From Csar"); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + + Either<Resource, ResponseFormat> result = null; + try { + Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> prepareForUpdate = null; + Resource preparedResource = null; + if (isUpdateYaml) { + + prepareForUpdate = updateExistingResourceByImport(newRresource, oldRresource, user, true, false); + + if (prepareForUpdate.isRight()) { + log.debug("Failed to prepare resource for update : {}", prepareForUpdate.right().value()); + result = Either.right(prepareForUpdate.right().value()); + return result; + } + preparedResource = prepareForUpdate.left().value().left; + String yamlFileName = toscaYamlCsarStatus.left().value().getKey(); + String yamlFileContents = toscaYamlCsarStatus.left().value().getValue(); + log.trace("YAML topology file found in CSAR, file name: {}, contents: {}", yamlFileName, yamlFileContents); + + // Either<Map<String, Resource>, ResponseFormat> + // parseNodeTypeInfoYamlEither = + // createResourcesFromYamlNodeTypesList(yamlFileName,preparedResource, + // yamlFileContents, user,false); + + Either<Map<String, Resource>, ResponseFormat> parseNodeTypeInfoYamlEither = this.handleNodeTypes(yamlFileName, preparedResource, user, yamlFileContents, csar.left().value(), false); + if (parseNodeTypeInfoYamlEither.isRight()) { + ResponseFormat responseFormat = parseNodeTypeInfoYamlEither.right().value(); + componentsUtils.auditResource(responseFormat, user, preparedResource, "", "", updateResource, null); + result = Either.right(responseFormat); + return result; + } + + Either<ParsedToscaYamlInfo, ResponseFormat> uploadComponentInstanceInfoMap = parseResourceInfoFromYaml(yamlFileName, preparedResource, yamlFileContents, user); + if (uploadComponentInstanceInfoMap.isRight()) { + ResponseFormat responseFormat = uploadComponentInstanceInfoMap.right().value(); + componentsUtils.auditResource(responseFormat, user, preparedResource, "", "", updateResource, null); + result = Either.right(responseFormat); + return result; + } + + Map<String, InputDefinition> inputs = uploadComponentInstanceInfoMap.left().value().getInputs(); + Either<Resource, ResponseFormat> createInputsOnResource = createInputsOnResource(preparedResource, user, inputs, true); + if (createInputsOnResource.isRight()) { + log.debug("failed to create resource inputs status is {}", createInputsOnResource.right().value()); + ResponseFormat responseFormat = createInputsOnResource.right().value(); + componentsUtils.auditResource(createInputsOnResource.right().value(), user, preparedResource, "", "", updateResource, null); + result = Either.right(responseFormat); + return result; + } + preparedResource = createInputsOnResource.left().value(); + + Map<String, UploadComponentInstanceInfo> instances = uploadComponentInstanceInfoMap.left().value().getInstances(); + Either<Resource, ResponseFormat> createResourcesInstancesEither = createResourceInstances(user, yamlFileName, preparedResource, instances, true, false, parseNodeTypeInfoYamlEither.left().value()); + if (createResourcesInstancesEither.isRight()) { + log.debug("failed to create resource instances status is {}", createResourcesInstancesEither.right().value()); + ResponseFormat responseFormat = createResourcesInstancesEither.right().value(); + componentsUtils.auditResource(createResourcesInstancesEither.right().value(), user, preparedResource, "", "", updateResource, null); + result = Either.right(responseFormat); + return result; + } + preparedResource = createResourcesInstancesEither.left().value(); + + createResourcesInstancesEither = createResourceInstancesRelations(user, yamlFileName, preparedResource, instances, true, false); + if (createResourcesInstancesEither.isRight()) { + log.debug("failed to create relation between resource instances status is {}", createResourcesInstancesEither.right().value()); + result = Either.right(createResourcesInstancesEither.right().value()); + return result; + } + + preparedResource = createResourcesInstancesEither.left().value(); + + Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesRes = groupBusinessLogic.validateUpdateVfGroupNames(uploadComponentInstanceInfoMap.left().value().getGroups(), preparedResource.getSystemName()); + if (validateUpdateVfGroupNamesRes.isRight()) { + + return Either.right(validateUpdateVfGroupNamesRes.right().value()); + } + // add groups to resource + Map<String, GroupDefinition> groups; + + if (!validateUpdateVfGroupNamesRes.left().value().isEmpty()) { + groups = validateUpdateVfGroupNamesRes.left().value(); + } else { + groups = uploadComponentInstanceInfoMap.left().value().getGroups(); + } + Either<Resource, ResponseFormat> updatedGroupsOnResource = updateGroupsOnResource(preparedResource, user, groups); + if (updatedGroupsOnResource.isRight()) { + + return updatedGroupsOnResource; + } + preparedResource = updatedGroupsOnResource.left().value(); + + } else { + Either<Resource, ResponseFormat> dataModelResponse = updateResourceMetadata(oldRresource.getUniqueId(), newRresource, user, oldRresource, false, true); + if (dataModelResponse.isRight()) { + log.debug("failed to update resource metadata {}", dataModelResponse.right().value()); + result = Either.right(dataModelResponse.right().value()); + return result; + } + + preparedResource = dataModelResponse.left().value(); + + } + + Either<Resource, ResponseFormat> createdCsarArtifactsEither = handleCsarArtifacts(preparedResource, user, csarUUID, csar.left().value(), createdArtifacts, ArtifactOperation.Update, false, true); + if (createdCsarArtifactsEither.isRight()) { + + return createdCsarArtifactsEither; + } + preparedResource = createdCsarArtifactsEither.left().value(); + + Either<List<ComponentInstance>, ResponseFormat> eitherSetPosition = compositionBusinessLogic.setPositionsForComponentInstances(preparedResource, user.getUserId()); + result = eitherSetPosition.isRight() ? Either.right(eitherSetPosition.right().value()) : Either.left(preparedResource); + + return result; + + } finally { + if (result == null || result.isRight()) { + log.warn("operation failed. do rollback"); + titanGenericDao.rollback(); + if (!createdArtifacts.isEmpty()) { + StorageOperationStatus deleteFromEsRes = artifactsBusinessLogic.deleteAllComponentArtifactsIfNotOnGraph(createdArtifacts); + if (!deleteFromEsRes.equals(StorageOperationStatus.OK)) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(deleteFromEsRes); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, oldRresource.getName()); + } + log.debug("component and all its artifacts were deleted, id = {}", oldRresource.getName()); + } + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + log.debug("unlock resource {}", lockedResourceId); + graphLockOperation.unlockComponent(lockedResourceId, NodeTypeEnum.Resource); + } + + } + + public Either<Resource, ResponseFormat> createResourceFromCsar(Resource resource, User user, AuditingActionEnum createResource, boolean inTransaction, Either<Map<String, byte[]>, StorageOperationStatus> csarUIPayload, String csarUUID) { + log.trace("************* created successfully from YAML, resource TOSCA "); + + Either<Map<String, byte[]>, StorageOperationStatus> csar = null; + if (csarUIPayload != null && csarUIPayload.left() != null && csarUIPayload.left().value() != null) { + csar = csarUIPayload; + } else { + csar = csarOperation.getCsar(csarUUID, user); + } + + Either<ImmutablePair<String, String>, ResponseFormat> toscaYamlCsarStatus = validateAndParseCsar(resource, user, csarUUID, csar); + if (toscaYamlCsarStatus.isRight()) { + return Either.right(toscaYamlCsarStatus.right().value()); + } + Either<String, ResponseFormat> toscaYamlChecksum = CsarValidationUtils.getToscaYamlChecksum(csar.left().value(), csarUUID, componentsUtils); + if (toscaYamlChecksum.isRight()) { + log.debug("Failed to calculate checksum for CSAR {}, error {}", csarUUID, toscaYamlChecksum.right().value()); + return Either.right(toscaYamlChecksum.right().value()); + } + resource.getComponentMetadataDefinition().getMetadataDataDefinition().setImportedToscaChecksum(toscaYamlChecksum.left().value()); + + String yamlFileName = toscaYamlCsarStatus.left().value().getKey(); + String yamlFileContents = toscaYamlCsarStatus.left().value().getValue(); + log.trace("YAML topology file found in CSAR, file name: {}, contents: {}", yamlFileName, yamlFileContents); + Either<Resource, ResponseFormat> createResourceFromYaml = createResourceFromYaml(resource, user, yamlFileContents, yamlFileName, csar.left().value(), csarUUID); + if (createResourceFromYaml.isRight()) { + log.debug("Couldn't create resource from YAML"); + return Either.right(createResourceFromYaml.right().value()); + } + + Resource vfResource = createResourceFromYaml.left().value(); + log.trace("*************VF Resource created successfully from YAML, resource TOSCA name: {}", vfResource.getToscaResourceName()); + return Either.left(vfResource); + } + + private Either<ImmutablePair<String, String>, ResponseFormat> validateAndParseCsar(Resource resource, User user, String csarUUID, Either<Map<String, byte[]>, StorageOperationStatus> csar) { + if (csar.isRight()) { + StorageOperationStatus value = csar.right().value(); + log.debug("Error when fetching csar with ID {}, error: {}", csarUUID, value); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Creating resource from CSAR: fetching CSAR with id " + csarUUID + " failed"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(value), csarUUID); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.CREATE_RESOURCE, null); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateCsarStatus = CsarValidationUtils.validateCsar(csar.left().value(), csarUUID, componentsUtils); + if (validateCsarStatus.isRight()) { + ResponseFormat responseFormat = validateCsarStatus.right().value(); + log.debug("Error when validate csar with ID {}, error: {}", csarUUID, responseFormat); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Creating resource from CSAR: fetching CSAR with id " + csarUUID + " failed"); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.CREATE_RESOURCE, null); + return Either.right(responseFormat); + } + + Either<ImmutablePair<String, String>, ResponseFormat> toscaYamlCsarStatus = CsarValidationUtils.getToscaYaml(csar.left().value(), csarUUID, componentsUtils); + + if (toscaYamlCsarStatus.isRight()) { + ResponseFormat responseFormat = toscaYamlCsarStatus.right().value(); + log.debug("Error when try to get csar toscayamlFile with csar ID {}, error: {}", csarUUID, responseFormat); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Creating resource from CSAR: fetching CSAR with id " + csarUUID + " failed"); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.CREATE_RESOURCE, null); + return Either.right(responseFormat); + } + return toscaYamlCsarStatus; + } + + private Either<Resource, ResponseFormat> validateResourceBeforeCreate(Resource resource, User user, boolean inTransaction) { + log.trace("validating resource before create"); + Either<User, ResponseFormat> eitherCreator = validateUser(user, "Create Resource", resource, AuditingActionEnum.CREATE_RESOURCE, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user.copyData(eitherCreator.left().value()); + + // validate user role + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, resource, new ArrayList<Role>(), AuditingActionEnum.CREATE_RESOURCE, null); + if (validateRes.isRight()) { + return Either.right(validateRes.right().value()); + } + // VF "derivedFrom" should be null (or ignored) + if (!resource.getResourceType().equals(ResourceTypeEnum.VF)) { + Either<Boolean, ResponseFormat> validateDerivedFromNotEmpty = validateDerivedFromNotEmpty(user, resource, AuditingActionEnum.CREATE_RESOURCE); + if (validateDerivedFromNotEmpty.isRight()) { + return Either.right(validateDerivedFromNotEmpty.right().value()); + } + } + return validateResourceBeforeCreate(resource, user, AuditingActionEnum.CREATE_RESOURCE, inTransaction); + + } + + public Either<Resource, ResponseFormat> createResourceFromYaml(Resource resource, User user, String topologyTemplateYaml, String yamlName, Map<String, byte[]> csar, String csarUUID) { + + List<ArtifactDefinition> createdArtifacts = new ArrayList<ArtifactDefinition>(); + log.trace("************* createResourceFromYaml before parse yaml "); + Either<ParsedToscaYamlInfo, ResponseFormat> parseResourceInfoFromYamlEither = parseResourceInfoFromYaml(yamlName, resource, topologyTemplateYaml, user); + if (parseResourceInfoFromYamlEither.isRight()) { + ResponseFormat responseFormat = parseResourceInfoFromYamlEither.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return Either.right(responseFormat); + } + log.trace("************* createResourceFromYaml after parse yaml "); + ParsedToscaYamlInfo parsedToscaYamlInfo = parseResourceInfoFromYamlEither.left().value(); + log.debug("The parsed tosca yaml info is {}", parsedToscaYamlInfo); + log.trace("************* createResourceFromYaml before create "); + Either<Resource, ResponseFormat> createdResourceResponse = createResourceAndRIsFromYaml(yamlName, resource, user, parsedToscaYamlInfo, AuditingActionEnum.IMPORT_RESOURCE, false, csarUUID, csar, createdArtifacts, topologyTemplateYaml); + log.trace("************* createResourceFromYaml after create "); + if (createdResourceResponse.isRight()) { + ResponseFormat responseFormat = createdResourceResponse.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return Either.right(responseFormat); + } + + return createdResourceResponse; + + } + + public Either<Map<String, Resource>, ResponseFormat> createResourcesFromYamlNodeTypesList(String yamlName, Resource resource, String resourceYml, User user, boolean needLock) { + + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(resourceYml); + + Either<String, ResultStatusEnum> tosca_version = ImportUtils.findFirstToscaStringElement(mappedToscaTemplate, ToscaTagNamesEnum.TOSCA_VERSION); + if (tosca_version.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_TEMPLATE); + return Either.right(responseFormat); + } + + Either<Map<String, Object>, ResultStatusEnum> eitherNodeTypes = ImportUtils.findFirstToscaMapElement(mappedToscaTemplate, ToscaTagNamesEnum.NODE_TYPES); + + Map<String, Resource> nodeTypesResources = new HashMap<>(); + Either<Map<String, Resource>, ResponseFormat> result = Either.left(nodeTypesResources); + + Map<String, Object> mapToConvert = new HashMap<String, Object>(); + mapToConvert.put(ToscaTagNamesEnum.TOSCA_VERSION.getElementName(), tosca_version.left().value()); + + if (eitherNodeTypes.isLeft()) { + + Iterator<Entry<String, Object>> nodesNameValue = eitherNodeTypes.left().value().entrySet().iterator(); + + while (nodesNameValue.hasNext()) { + + Entry<String, Object> nodeType = nodesNameValue.next(); + log.trace("************* Going to create node {}", nodeType.getKey()); + Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> resourceCreated = this.createNodeTypeResourceFromYaml(yamlName, nodeType, user, mapToConvert, resource, needLock); + log.trace("************* finished to create node {}", nodeType.getKey()); + if (resourceCreated.isRight()) { + return Either.right(resourceCreated.right().value()); + } + Resource vfcCreated = resourceCreated.left().value().getLeft(); + + nodeTypesResources.put(nodeType.getKey(), vfcCreated); + mapToConvert.remove(ToscaTagNamesEnum.NODE_TYPES.getElementName()); + + } + } + + return result; + } + + private String getNodeTypeActualName(String fullName) { + String nameWithouNamespacePrefix = fullName.substring(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX.length()); + String[] findTypes = nameWithouNamespacePrefix.split("\\."); + String resourceType = findTypes[0]; + return nameWithouNamespacePrefix.substring(resourceType.length()); + } + + private Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> createNodeTypeResourceFromYaml(String yamlName, Entry<String, Object> nodeNameValue, User user, Map<String, Object> mapToConvert, Resource resourceVf, boolean needLock) { + + Either<UploadResourceInfo, ResponseFormat> resourceMetaData = fillResourceMetadata(yamlName, resourceVf, nodeNameValue.getKey(), user); + if (resourceMetaData.isRight()) { + return Either.right(resourceMetaData.right().value()); + } + + // We need to create a Yaml from each node_types in order to create + // resource from each node type using import normative flow. + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + + Map<String, Object> singleVfc = new HashMap<>(); + + String actualName = this.getNodeTypeActualName(nodeNameValue.getKey()); + if (!actualName.startsWith(ImportUtils.Constants.ABSTRACT_NODE)) { + actualName = "." + ImportUtils.Constants.ABSTRACT_NODE + actualName; + } + + // Setting tosca name + String toscaResourceName = ImportUtils.Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX + resourceMetaData.left().value().getResourceType().toLowerCase() + '.' + resourceVf.getSystemName() + actualName; + singleVfc.put(toscaResourceName, nodeNameValue.getValue()); + mapToConvert.put(ToscaTagNamesEnum.NODE_TYPES.getElementName(), singleVfc); + + String singleVfcYaml = yaml.dumpAsMap(mapToConvert); + + Either<User, ResponseFormat> eitherCreator = validateUser(user, "CheckIn Resource", resourceVf, AuditingActionEnum.CHECKIN_RESOURCE, true); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + return this.createResourceFromNodeType(singleVfcYaml, resourceMetaData.left().value(), user, true, needLock); + } + + public Either<Boolean, ResponseFormat> validateResourceCreationFromNodeType(Resource resource, User creator) { + + Either<Boolean, ResponseFormat> validateDerivedFromNotEmpty = this.validateDerivedFromNotEmpty(creator, resource, AuditingActionEnum.CREATE_RESOURCE); + if (validateDerivedFromNotEmpty.isRight()) { + return Either.right(validateDerivedFromNotEmpty.right().value()); + } + return Either.left(true); + } + + public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> createResourceFromNodeType(String nodeTypeYaml, UploadResourceInfo resourceMetaData, User creator, boolean isInTransaction, boolean needLock) { + + LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction("certification on import", LifecycleChanceActionEnum.CREATE_FROM_CSAR); + Function<Resource, Either<Boolean, ResponseFormat>> validator = (resource) -> this.validateResourceCreationFromNodeType(resource, creator); + return this.resourceImportManager.importCertifiedResource(nodeTypeYaml, resourceMetaData, creator, validator, lifecycleChangeInfo, isInTransaction, true, needLock); + } + + private Either<UploadResourceInfo, ResponseFormat> fillResourceMetadata(String yamlName, Resource resourceVf, String nodeTypeName, User user) { + UploadResourceInfo resourceMetaData = new UploadResourceInfo(); + + // validate nodetype name prefix + if (!nodeTypeName.startsWith(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX)) { + log.debug("invalid nodeTypeName:{} does not start with {}.", nodeTypeName, Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_NODE_TEMPLATE, yamlName, resourceMetaData.getName(), nodeTypeName); + return Either.right(responseFormat); + } + + String actualName = this.getNodeTypeActualName(nodeTypeName); + String namePrefix = nodeTypeName.replace(actualName, ""); + String resourceType = namePrefix.substring(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX.length()); + + // if we import from csar, the node_type name can be + // org.openecomp.resource.abstract.node_name - in this case we always + // create a vfc + if (resourceType.equals(Constants.ABSTRACT)) { + resourceType = ResourceTypeEnum.VFC.name().toLowerCase(); + } + // validating type + if (!ResourceTypeEnum.contains(resourceType.toUpperCase())) { + log.debug("invalid resourceType:{} the type is not one of the valide types:{}.", resourceType.toUpperCase(), ResourceTypeEnum.values()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_NODE_TEMPLATE, yamlName, resourceMetaData.getName(), nodeTypeName); + return Either.right(responseFormat); + } + + // Setting name + resourceMetaData.setName(resourceVf.getSystemName() + actualName); + + // Setting type from name + String type = resourceType.toUpperCase(); + resourceMetaData.setResourceType(type); + + resourceMetaData.setDescription(ImportUtils.Constants.INNER_VFC_DESCRIPTION); + resourceMetaData.setIcon(ImportUtils.Constants.DEFAULT_ICON); + resourceMetaData.setContactId(user.getUserId()); + resourceMetaData.setVendorName(resourceVf.getVendorName()); + resourceMetaData.setVendorRelease(resourceVf.getVendorRelease()); + + // Setting tag + List<String> tags = new ArrayList<>(); + tags.add(resourceMetaData.getName()); + resourceMetaData.setTags(tags); + + // Setting category + CategoryDefinition category = new CategoryDefinition(); + category.setName(ImportUtils.Constants.ABSTRACT_CATEGORY_NAME); + SubCategoryDefinition subCategory = new SubCategoryDefinition(); + subCategory.setName(ImportUtils.Constants.ABSTRACT_SUBCATEGORY); + category.addSubCategory(subCategory); + List<CategoryDefinition> categories = new ArrayList<>(); + categories.add(category); + resourceMetaData.setCategories(categories); + + return Either.left(resourceMetaData); + } + + private Either<Resource, ResponseFormat> createResourceAndRIsFromYaml(String yamlName, Resource resource, User user, ParsedToscaYamlInfo parsedToscaYamlInfo, AuditingActionEnum actionEnum, boolean isNormative, String csarUUID, + Map<String, byte[]> csar, List<ArtifactDefinition> createdArtifacts, String topologyTemplateYaml) { + + boolean result = true; + + Either<Boolean, ResponseFormat> lockResult = lockComponentByName(resource.getSystemName(), resource, "Create Resource"); + if (lockResult.isRight()) { + ResponseFormat responseFormat = lockResult.right().value(); + return Either.right(responseFormat); + } + log.debug("name is locked {} status = {}", resource.getSystemName(), lockResult); + + try { + log.trace("************* createResourceFromYaml before full create resource {}", yamlName); + Either<Resource, ResponseFormat> createResourcesEither = createResourceTransaction(resource, user, actionEnum, isNormative, true); + log.trace("************* createResourceFromYaml after full create resource {}", yamlName); + if (createResourcesEither.isRight()) { + result = false; + return createResourcesEither; + } + resource = createResourcesEither.left().value(); + // add groups to resource + log.trace("************* Going to add inputs from yaml {}", yamlName); + + Map<String, InputDefinition> inputs = parsedToscaYamlInfo.getInputs(); + Either<Resource, ResponseFormat> createInputsOnResource = createInputsOnResource(resource, user, inputs, true); + if (createInputsOnResource.isRight()) { + result = false; + return createInputsOnResource; + } + resource = createInputsOnResource.left().value(); + log.trace("************* Finish to add inputs from yaml {}", yamlName); + + Map<String, UploadComponentInstanceInfo> uploadComponentInstanceInfoMap = parsedToscaYamlInfo.getInstances(); + log.trace("************* Going to create nodes, RI's and Relations from yaml {}", yamlName); + createResourcesEither = createRIAndRelationsFromYaml(yamlName, resource, user, uploadComponentInstanceInfoMap, actionEnum, topologyTemplateYaml, csar, csarUUID); + log.trace("************* Finished to create nodes, RI and Relation from yaml {}", yamlName); + if (createResourcesEither.isRight()) { + result = false; + return createResourcesEither; + } + + resource = createResourcesEither.left().value(); + // validate update vf module group names + Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesRes = groupBusinessLogic.validateUpdateVfGroupNames(parsedToscaYamlInfo.getGroups(), resource.getSystemName()); + if (validateUpdateVfGroupNamesRes.isRight()) { + result = false; + return Either.right(validateUpdateVfGroupNamesRes.right().value()); + } + // add groups to resource + Map<String, GroupDefinition> groups; + log.trace("************* Going to add groups from yaml {}", yamlName); + + if (!validateUpdateVfGroupNamesRes.left().value().isEmpty()) { + groups = validateUpdateVfGroupNamesRes.left().value(); + } else { + groups = parsedToscaYamlInfo.getGroups(); + } + Either<Resource, ResponseFormat> createGroupsOnResource = createGroupsOnResource(resource, user, groups); + if (createGroupsOnResource.isRight()) { + result = false; + return createGroupsOnResource; + } + resource = createGroupsOnResource.left().value(); + log.trace("************* Finished to add groups from yaml {}", yamlName); + + log.trace("************* Going to add artifacts from yaml {}", yamlName); + Either<Resource, ResponseFormat> createdCsarArtifactsEither = this.handleCsarArtifacts(resource, user, csarUUID, csar, createdArtifacts, ArtifactOperation.Create, false, true); + log.trace("************* Finished to add artifacts from yaml {}", yamlName); + if (createdCsarArtifactsEither.isRight()) { + result = false; + return createdCsarArtifactsEither; + } + resource = createdCsarArtifactsEither.left().value(); + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + ASDCKpiApi.countCreatedResourcesKPI(); + return Either.left(resource); + + } finally { + if (!result) { + log.warn("operation failed. do rollback"); + titanGenericDao.rollback(); + if (!createdArtifacts.isEmpty()) { + StorageOperationStatus deleteFromEsRes = artifactsBusinessLogic.deleteAllComponentArtifactsIfNotOnGraph(createdArtifacts); + if (!deleteFromEsRes.equals(StorageOperationStatus.OK)) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(deleteFromEsRes); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, resource.getName()); + } + log.debug("component and all its artifacts were deleted, id = {}", resource.getName()); + } + + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + + graphLockOperation.unlockComponentByName(resource.getSystemName(), resource.getUniqueId(), NodeTypeEnum.Resource); + + } + + } + + private Either<Resource, ResponseFormat> createGroupsOnResource(Resource resource, User user, Map<String, GroupDefinition> groups) { + if (groups != null && false == groups.isEmpty()) { + Either<List<GroupDefinition>, ResponseFormat> mergeGroupsUsingResource = updateGroupMembersUsingResource(groups, resource); + + if (mergeGroupsUsingResource.isRight()) { + log.debug("Failed to prepare groups for creation"); + return Either.right(mergeGroupsUsingResource.right().value()); + } + List<GroupDefinition> groupsAsList = mergeGroupsUsingResource.left().value(); + + // Either<List<GroupDefinition>, ResponseFormat> createGroups = + // groupBusinessLogic.createGroups( + // resource.getUniqueId(), user.getUserId(), + // ComponentTypeEnum.RESOURCE, groupsAsList, false, + // true); + // In this method we assume all instances exists in resource + Either<List<GroupDefinition>, ResponseFormat> createGroups = groupBusinessLogic.createGroups(resource, user, ComponentTypeEnum.RESOURCE, groupsAsList, true); + if (createGroups.isRight()) { + return Either.right(createGroups.right().value()); + } + } else { + return Either.left(resource); + } + + Either<Resource, StorageOperationStatus> updatedResource = resourceOperation.getResource(resource.getUniqueId(), true); + if (updatedResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(updatedResource.right().value()), resource); + return Either.right(responseFormat); + } + return Either.left(updatedResource.left().value()); + } + + private Either<Resource, ResponseFormat> updateGroupsOnResource(Resource resource, User user, Map<String, GroupDefinition> groups) { + if (groups != null && false == groups.isEmpty()) { + List<GroupDefinition> groupsFromResource = resource.getGroups(); + Either<List<GroupDefinition>, ResponseFormat> mergeGroupsUsingResource = updateGroupMembersUsingResource(groups, resource); + + if (mergeGroupsUsingResource.isRight()) { + log.debug("Failed to prepare groups for creation"); + return Either.right(mergeGroupsUsingResource.right().value()); + } + List<GroupDefinition> groupsAsList = mergeGroupsUsingResource.left().value(); + List<GroupDefinition> groupsToUpdate = new ArrayList<GroupDefinition>(); + List<GroupDefinition> groupsToDelete = new ArrayList<GroupDefinition>(); + List<GroupDefinition> groupsToCreate = new ArrayList<GroupDefinition>(); + if (groupsFromResource != null && !groupsFromResource.isEmpty()) { + for (GroupDefinition group : groupsAsList) { + Optional<GroupDefinition> op = groupsFromResource.stream().filter(p -> p.getName().equals(group.getName())).findAny(); + if (op.isPresent()) { + GroupDefinition groupToUpdate = op.get(); + groupToUpdate.setMembers(group.getMembers()); + groupsToUpdate.add(groupToUpdate); + } else { + groupsToCreate.add(group); + } + } + for (GroupDefinition group : groupsFromResource) { + Optional<GroupDefinition> op = groupsAsList.stream().filter(p -> p.getName().equals(group.getName())).findAny(); + if (!op.isPresent() && (group.getArtifacts() == null || group.getArtifacts().isEmpty())) { + + groupsToDelete.add(group); + } + + } + } else + groupsToCreate.addAll(groupsAsList); + + if (!groupsToCreate.isEmpty()) { + Either<List<GroupDefinition>, ResponseFormat> createGroups = groupBusinessLogic.createGroups(resource, user, ComponentTypeEnum.RESOURCE, groupsToCreate, true); + + if (createGroups.isRight()) { + return Either.right(createGroups.right().value()); + } + } + + if (!groupsToDelete.isEmpty()) { + for (GroupDefinition group : groupsToDelete) { + Either<GroupDefinition, StorageOperationStatus> deleteGroupEither = groupOperation.deleteGroup(group.getUniqueId(), true); + if (deleteGroupEither.isRight()) { + StorageOperationStatus storageOperationStatus = deleteGroupEither.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus); + log.debug("Failed to delete group {} under component {}, error: {}", group.getUniqueId(), resource.getNormalizedName(), actionStatus.name()); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + } + } + } + if (groupsToUpdate != null && !groupsToUpdate.isEmpty()) { + Either<List<GroupDefinition>, ResponseFormat> assotiateGroupEither = groupBusinessLogic.associateMembersToGroup(resource.getUniqueId(), user.getUserId(), ComponentTypeEnum.RESOURCE, groupsToUpdate, false, true); + if (assotiateGroupEither.isRight()) { + log.debug("Failed to associate artifacts to groups. Status is {} ", assotiateGroupEither.right().value()); + return Either.right(assotiateGroupEither.right().value()); + + } + List<GroupDefinition> updatedGroups = assotiateGroupEither.left().value(); + List<String> groupsId = updatedGroups.stream().map(e -> e.getUniqueId()).collect(Collectors.toList()); + + Either<List<GroupDefinition>, StorageOperationStatus> updateVersionEither = groupBusinessLogic.updateGroupVersion(groupsId, true); + if (updateVersionEither.isRight()) { + log.debug("Failed to update groups version. Status is {} ", updateVersionEither.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(updateVersionEither.right().value()), resource); + return Either.right(responseFormat); + + } + } + + } else { + return Either.left(resource); + } + + Either<Resource, StorageOperationStatus> updatedResource = resourceOperation.getResource(resource.getUniqueId(), true); + if (updatedResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(updatedResource.right().value()), resource); + return Either.right(responseFormat); + } + return Either.left(updatedResource.left().value()); + } + + private Either<Resource, ResponseFormat> createInputsOnResource(Resource resource, User user, Map<String, InputDefinition> inputs, boolean inTransaction) { + if (inputs != null && false == inputs.isEmpty()) { + List<InputDefinition> inputsAsList = new ArrayList<InputDefinition>(); + for (Entry<String, InputDefinition> entry : inputs.entrySet()) { + InputDefinition input = entry.getValue(); + input.setName(entry.getKey()); + inputsAsList.add(input); + } + Either<List<InputDefinition>, ResponseFormat> createGroups = inputsBusinessLogic.createInputsInGraph(inputsAsList, resource, user, inTransaction); + if (createGroups.isRight()) { + return Either.right(createGroups.right().value()); + } + } else { + return Either.left(resource); + } + + Either<Resource, StorageOperationStatus> updatedResource = resourceOperation.getResource(resource.getUniqueId(), true); + if (updatedResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(updatedResource.right().value()), resource); + return Either.right(responseFormat); + } + return Either.left(updatedResource.left().value()); + } + + private Either<List<GroupDefinition>, ResponseFormat> updateGroupMembersUsingResource(Map<String, GroupDefinition> groups, Resource component) { + + List<GroupDefinition> result = new ArrayList<>(); + + List<ComponentInstance> componentInstances = component.getComponentInstances(); + + if (groups != null) { + for (Entry<String, GroupDefinition> entry : groups.entrySet()) { + String groupName = entry.getKey(); + + GroupDefinition groupDefinition = entry.getValue(); + + GroupDefinition updatedGroupDefinition = new GroupDefinition(groupDefinition); + updatedGroupDefinition.setMembers(null); + + // get the members of the group + Map<String, String> members = groupDefinition.getMembers(); + if (members != null) { + Set<String> compInstancesNames = members.keySet(); + + if (componentInstances == null || true == componentInstances.isEmpty()) { + String membersAstString = compInstancesNames.stream().collect(Collectors.joining(",")); + log.debug("The members {} in group {} cannot be found in component {}. There are no component instances", membersAstString, groupName, component.getNormalizedName()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, membersAstString, groupName, component.getNormalizedName(), getComponentTypeForResponse(component))); + } + // Find all component instances with the member names + Map<String, String> memberNames = componentInstances.stream().collect(Collectors.toMap(ComponentInstance::getName, ComponentInstance::getUniqueId)); + memberNames.putAll(groups.keySet().stream().collect(Collectors.toMap(g -> g, g -> ""))); + Map<String, String> relevantInstances = memberNames.entrySet().stream().filter(n -> compInstancesNames.contains(n.getKey())).collect(Collectors.toMap(n -> n.getKey(), n -> n.getValue())); + + if (relevantInstances == null || relevantInstances.size() != compInstancesNames.size()) { + + List<String> foundMembers = new ArrayList<>(); + if (relevantInstances != null) { + foundMembers = relevantInstances.keySet().stream().collect(Collectors.toList()); + } + compInstancesNames.removeAll(foundMembers); + String membersAstString = compInstancesNames.stream().collect(Collectors.joining(",")); + log.debug("The members {} in group {} cannot be found in component {}", membersAstString, groupName, component.getNormalizedName()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, membersAstString, groupName, component.getNormalizedName(), getComponentTypeForResponse(component))); + } + + updatedGroupDefinition.setMembers(relevantInstances); + } + + result.add(updatedGroupDefinition); + } + } + return Either.left(result); + } + + private Either<Resource, ResponseFormat> createRIAndRelationsFromYaml(String yamlName, Resource resource, User user, Map<String, UploadComponentInstanceInfo> uploadComponentInstanceInfoMap, AuditingActionEnum actionEnum, + String topologyTemplateYaml, Map<String, byte[]> csar, String csarUUID) { + + Either<Resource, ResponseFormat> result; + Either<Resource, ResponseFormat> createResourcesInstancesEither; + log.debug("************* Going to create all nodes {}", yamlName); + Either<Map<String, Resource>, ResponseFormat> createdResourcesFromdNodeTypeMap = this.handleNodeTypes(yamlName, resource, user, topologyTemplateYaml, csar, false); + log.debug("************* Finished to create all nodes {}", yamlName); + if (createdResourcesFromdNodeTypeMap.isRight()) { + log.debug("failed to resources from node types status is {}", createdResourcesFromdNodeTypeMap.right().value()); + return Either.right(createdResourcesFromdNodeTypeMap.right().value()); + } + + log.debug("************* Going to create all resource instances {}", yamlName); + createResourcesInstancesEither = createResourceInstances(user, yamlName, resource, uploadComponentInstanceInfoMap, true, false, createdResourcesFromdNodeTypeMap.left().value()); + + log.debug("************* Finished to create all resource instances {}", yamlName); + if (createResourcesInstancesEither.isRight()) { + log.debug("failed to create resource instances status is {}", createResourcesInstancesEither.right().value()); + result = createResourcesInstancesEither; + return createResourcesInstancesEither; + } + resource = createResourcesInstancesEither.left().value(); + log.debug("************* Going to create all relations {}", yamlName); + createResourcesInstancesEither = createResourceInstancesRelations(user, yamlName, resource, uploadComponentInstanceInfoMap, true, false); + + log.debug("************* Finished to create all relations {}", yamlName); + + if (createResourcesInstancesEither.isRight()) { + log.debug("failed to create relation between resource instances status is {}", createResourcesInstancesEither.right().value()); + result = createResourcesInstancesEither; + return result; + } else { + resource = createResourcesInstancesEither.left().value(); + } + + log.debug("************* Going to create positions {}", yamlName); + Either<List<ComponentInstance>, ResponseFormat> eitherSetPosition = compositionBusinessLogic.setPositionsForComponentInstances(resource, user.getUserId()); + log.debug("************* Finished to set positions {}", yamlName); + result = eitherSetPosition.isRight() ? Either.right(eitherSetPosition.right().value()) : Either.left(resource); + + return result; + } + + private Either<Map<String, Resource>, ResponseFormat> handleNodeTypes(String yamlName, Resource resource, User user, String topologyTemplateYaml, Map<String, byte[]> csar, boolean needLock) { + + Map<String, Resource> createdResourcesFromdNodeTypeMap = new HashMap<>(); + Either<Map<String, Resource>, ResponseFormat> result = Either.left(createdResourcesFromdNodeTypeMap); + + String yamlFileName = Constants.GLOBAL_SUBSTITUTION_TYPE_SERVICE_TEMPLATE; + + if (csar != null && csar.containsKey(yamlFileName)) { + byte[] yamlFileBytes = csar.get(yamlFileName); + String globalTypesYaml = new String(yamlFileBytes, StandardCharsets.UTF_8); + Either<Map<String, Resource>, ResponseFormat> createdNodeTypesFromGlobalTypesTemplateEither = this.createResourcesFromYamlNodeTypesList(yamlFileName, resource, globalTypesYaml, user, needLock); + if (createdNodeTypesFromGlobalTypesTemplateEither.isRight()) { + ResponseFormat responseFormat = createdNodeTypesFromGlobalTypesTemplateEither.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return Either.right(responseFormat); + } + createdResourcesFromdNodeTypeMap.putAll(createdNodeTypesFromGlobalTypesTemplateEither.left().value()); + } + + Either<Map<String, Resource>, ResponseFormat> createdNodeTypeFromMainTemplateEither = createResourcesFromYamlNodeTypesList(yamlName, resource, topologyTemplateYaml, user, needLock); + if (createdNodeTypeFromMainTemplateEither.isRight()) { + ResponseFormat responseFormat = createdNodeTypeFromMainTemplateEither.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return Either.right(responseFormat); + } + + createdResourcesFromdNodeTypeMap.putAll(createdNodeTypeFromMainTemplateEither.left().value()); + + // add the created node types to the cache although they are not in the + // graph. + createdResourcesFromdNodeTypeMap.values().stream().forEach(p -> cacheManagerOperation.storeComponentInCache(p, NodeTypeEnum.Resource)); + + return result; + } + + private Either<Resource, ResponseFormat> handleCsarArtifacts(Resource resource, User user, String csarUUID, Map<String, byte[]> csar, List<ArtifactDefinition> createdArtifacts, ArtifactOperation artifactOperation, boolean shouldLock, + boolean inTransaction) { + + if (csar != null) { + String vendorLicenseModelId = null; + String vfLicenseModelId = null; + + if (artifactOperation.equals(ArtifactOperation.Update)) { + Map<String, ArtifactDefinition> deploymentArtifactsMap = resource.getDeploymentArtifacts(); + if (deploymentArtifactsMap != null && !deploymentArtifactsMap.isEmpty()) { + for (Entry<String, ArtifactDefinition> artifactEntry : deploymentArtifactsMap.entrySet()) { + if (artifactEntry.getValue().getArtifactName().equalsIgnoreCase(Constants.VENDOR_LICENSE_MODEL)) + vendorLicenseModelId = artifactEntry.getValue().getUniqueId(); + if (artifactEntry.getValue().getArtifactName().equalsIgnoreCase(Constants.VF_LICENSE_MODEL)) + vfLicenseModelId = artifactEntry.getValue().getUniqueId(); + } + } + + } + createOrUpdateLicenseArtifact(resource, user, csarUUID, csar, Constants.VENDOR_LICENSE_MODEL, ArtifactTypeEnum.VENDOR_LICENSE.getType(), Constants.VENDOR_LICENSE_LABEL, Constants.VENDOR_LICENSE_DISPLAY_NAME, + Constants.VENDOR_LICENSE_DESCRIPTION, vendorLicenseModelId, artifactOperation, shouldLock, inTransaction); + createOrUpdateLicenseArtifact(resource, user, csarUUID, csar, Constants.VF_LICENSE_MODEL, ArtifactTypeEnum.VF_LICENSE.getType(), Constants.VF_LICENSE_LABEL, Constants.VF_LICENSE_DISPLAY_NAME, Constants.VF_LICENSE_DESCRIPTION, + vfLicenseModelId, artifactOperation, shouldLock, inTransaction); + Either<ImmutablePair<String, String>, ResponseFormat> artifacsMetaCsarStatus = CsarValidationUtils.getArtifactsMeta(csar, csarUUID, componentsUtils); + if (artifacsMetaCsarStatus.isLeft()) { + + String artifactsFileName = artifacsMetaCsarStatus.left().value().getKey(); + String artifactsContents = artifacsMetaCsarStatus.left().value().getValue(); + Either<Resource, ResponseFormat> createArtifactsFromCsar = Either.left(resource); + if (artifactOperation.equals(ArtifactOperation.Create)) + createArtifactsFromCsar = createResourceArtifactsFromCsar(csarUUID, csar, resource, user, artifactsContents, artifactsFileName, createdArtifacts, shouldLock, inTransaction); + else + createArtifactsFromCsar = updateResourceArtifactsFromCsar(csarUUID, csar, resource, user, artifactsContents, artifactsFileName, createdArtifacts, shouldLock, inTransaction); + if (createArtifactsFromCsar.isRight()) { + log.debug("Couldn't create artifacts from artifacts.meta"); + return Either.right(createArtifactsFromCsar.right().value()); + } + + resource = createArtifactsFromCsar.left().value(); + } else { + List<GroupDefinition> groupsToDelete = resource.getGroups(); + + if (groupsToDelete != null && !groupsToDelete.isEmpty()) { + Set<String> artifactsToDelete = new HashSet<String>(); + for (GroupDefinition group : groupsToDelete) { + List<String> artifacts = group.getArtifacts(); + if (artifacts != null) { + artifactsToDelete.addAll(artifacts); + Either<GroupDefinition, StorageOperationStatus> deleteGroupEither = groupOperation.deleteGroup(group.getUniqueId(), inTransaction); + if (deleteGroupEither.isRight()) { + StorageOperationStatus storageOperationStatus = deleteGroupEither.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus); + log.debug("Failed to delete group {} under component {}, error: {}", group.getUniqueId(), resource.getNormalizedName(), actionStatus.name()); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + } + } + } + for (String artifactId : artifactsToDelete) { + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDelete = artifactsBusinessLogic.handleDelete(resource.getUniqueId(), artifactId, user, AuditingActionEnum.ARTIFACT_DELETE, ComponentTypeEnum.RESOURCE, + resource, null, null, shouldLock, inTransaction); + if (handleDelete.isRight()) { + log.debug("Couldn't delete artifact {}", artifactId); + return Either.right(handleDelete.right().value()); + } + + } + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getResource(resource.getUniqueId(), inTransaction); + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + return Either.right(responseFormat); + + } + resource = eitherGerResource.left().value(); + } + } + } + return Either.left(resource); + } + + private Either<Boolean, ResponseFormat> createOrUpdateLicenseArtifact(Resource resource, User user, String csarUUID, Map<String, byte[]> csar, String artifactFileName, String artifactType, String artifactLabel, String artifactDisplayName, + String artifactDescription, String artifactId, ArtifactOperation operation, boolean shouldLock, boolean inTransaction) { + byte[] artifactFileBytes = null; + + if (csar.containsKey(Constants.ARTIFACTS + artifactFileName)) { + artifactFileBytes = csar.get(Constants.ARTIFACTS + artifactFileName); + } + Either<Boolean, ResponseFormat> result = Either.left(true); + if (operation.equals(ArtifactOperation.Update)) { + if (artifactId != null && !artifactId.isEmpty() && artifactFileBytes == null) { + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDelete = artifactsBusinessLogic.handleDelete(resource.getUniqueId(), artifactId, user, AuditingActionEnum.ARTIFACT_DELETE, ComponentTypeEnum.RESOURCE, resource, null, + null, shouldLock, inTransaction); + if (handleDelete.isRight()) { + result = Either.right(handleDelete.right().value()); + } + return result; + } + + if ((artifactId == null || artifactId.isEmpty()) && artifactFileBytes != null) { + operation = ArtifactOperation.Create; + } + + } + if (artifactFileBytes != null) { + Map<String, Object> vendorLicenseModelJson = buildJsonForUpdateArtifact(artifactId, artifactFileName, artifactType, artifactLabel, artifactDisplayName, artifactDescription, artifactFileBytes, null); + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> vfLicenceArtifactCreateEither = createOrUpdateCsarArtifactFromJson(resource, user, vendorLicenseModelJson, operation, shouldLock, inTransaction); + + if (vfLicenceArtifactCreateEither.isRight()) { + BeEcompErrorManager.getInstance().logInternalFlowError("UploadLicenseArtifact", "Failed to upload license artifact: " + artifactFileName + "With csar uuid: " + csarUUID, ErrorSeverity.WARNING); + return Either.right(vfLicenceArtifactCreateEither.right().value()); + } + } + return result; + } + + private Either<Either<ArtifactDefinition, Operation>, ResponseFormat> createOrUpdateCsarArtifactFromJson(Resource resource, User user, Map<String, Object> json, ArtifactOperation operation, boolean shoudLock, boolean inTransaction) { + + String jsonStr = gson.toJson(json); + + String origMd5 = GeneralUtility.calculateMD5ByString(jsonStr); + ArtifactDefinition artifactDefinitionFromJson = RepresentationUtils.convertJsonToArtifactDefinition(jsonStr, ArtifactDefinition.class); + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> uploadArtifactToService = artifactsBusinessLogic.handleArtifactRequest(resource.getUniqueId(), user.getUserId(), ComponentTypeEnum.RESOURCE, operation, + artifactDefinitionFromJson.getUniqueId(), artifactDefinitionFromJson, origMd5, jsonStr, null, null, null, null, shoudLock, inTransaction); + if (uploadArtifactToService.isRight()) + return Either.right(uploadArtifactToService.right().value()); + + return Either.left(uploadArtifactToService.left().value()); + } + + public Either<Resource, ResponseFormat> updateResourceArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, String artifactsMetaFile, String artifactsMetaFileName, List<ArtifactDefinition> createdNewArtifacts, + boolean shouldLock, boolean inTransaction) { + + Either<Map<String, List<ArtifactTemplateInfo>>, ResponseFormat> parseResourceInfoFromYamlEither = parseResourceArtifactsInfoFromFile(resource, artifactsMetaFile, artifactsMetaFileName, user); + if (parseResourceInfoFromYamlEither.isRight()) { + ResponseFormat responseFormat = parseResourceInfoFromYamlEither.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return Either.right(responseFormat); + } + + List<GroupDefinition> groups = resource.getGroups(); + Map<String, ArtifactDefinition> deplymentArtifact = resource.getDeploymentArtifacts(); + List<ArtifactDefinition> createdDeplymentArtifactsAfterDelete = new ArrayList<ArtifactDefinition>(); + if (deplymentArtifact != null && !deplymentArtifact.isEmpty()) { + for (Entry<String, ArtifactDefinition> entry : deplymentArtifact.entrySet()) { + createdDeplymentArtifactsAfterDelete.add(entry.getValue()); + } + } + int labelCounter = createdDeplymentArtifactsAfterDelete.size(); + + if (deplymentArtifact == null || deplymentArtifact.isEmpty()) { + if (groups != null && !groups.isEmpty()) { + for (GroupDefinition group : groups) { + if (group.getArtifacts() != null && !group.getArtifacts().isEmpty()) { + log.debug("failed to update artifacts from csar. List of emty but group not empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + return Either.right(responseFormat); + } + } + } + return createResourceArtifacts(csarUUID, csar, resource, user, parseResourceInfoFromYamlEither.left().value(), AuditingActionEnum.CREATE_RESOURCE, createdNewArtifacts, shouldLock, inTransaction); + } + // find artifacts to delete + Set<String> artifactNotInGroupSet = findArtifactsNotInGroupToDelete(groups, createdDeplymentArtifactsAfterDelete); + + // delete all artifacts which not in groups + if (!artifactNotInGroupSet.isEmpty()) { + for (String artifactId : artifactNotInGroupSet) { + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDelete = artifactsBusinessLogic.handleDelete(resource.getUniqueId(), artifactId, user, AuditingActionEnum.ARTIFACT_DELETE, ComponentTypeEnum.RESOURCE, resource, null, + null, shouldLock, inTransaction); + if (handleDelete.isRight()) { + return Either.right(handleDelete.right().value()); + } + + } + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getResource(resource.getUniqueId(), inTransaction); + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + return Either.right(responseFormat); + + } + + resource = eitherGerResource.left().value(); + deplymentArtifact = resource.getDeploymentArtifacts(); + + createdDeplymentArtifactsAfterDelete.clear(); + if (deplymentArtifact != null && !deplymentArtifact.isEmpty()) { + for (Entry<String, ArtifactDefinition> entry : deplymentArtifact.entrySet()) { + createdDeplymentArtifactsAfterDelete.add(entry.getValue()); + } + } + } + + // find master in group + Map<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>> groupArtifact = findMasterArtifactInGroup(groups, deplymentArtifact); + + ////////////////////////////////////// create set parsed + ////////////////////////////////////// artifacts/////////////////////////////////////////// + Map<String, List<ArtifactTemplateInfo>> parsedArtifactsMap = parseResourceInfoFromYamlEither.left().value(); + Collection<List<ArtifactTemplateInfo>> parsedArifactsCollection = parsedArtifactsMap.values(); + Map<ArtifactTemplateInfo, Set<ArtifactTemplateInfo>> parsedGroup = new HashMap<ArtifactTemplateInfo, Set<ArtifactTemplateInfo>>(); + + for (List<ArtifactTemplateInfo> parsedGroupTemplateList : parsedArifactsCollection) { + for (ArtifactTemplateInfo parsedGroupTemplate : parsedGroupTemplateList) { + parsedGroupTemplate.setGroupName(""); + Set<ArtifactTemplateInfo> parsedArtifactsNames = new HashSet<ArtifactTemplateInfo>(); + parsedArtifactsNames.add(parsedGroupTemplate); + List<ArtifactTemplateInfo> relatedGroupTemplateList = parsedGroupTemplate.getRelatedArtifactsInfo(); + if (relatedGroupTemplateList != null && !relatedGroupTemplateList.isEmpty()) { + createArtifactsGroupSet(parsedGroupTemplateList, parsedArtifactsNames); + } + parsedGroup.put(parsedGroupTemplate, parsedArtifactsNames); + } + } + + ///////////////////////////////// find artifacts to + ///////////////////////////////// delete//////////////////////////////////////////////////// + + Set<ArtifactDefinition> artifactsToDelete = new HashSet<ArtifactDefinition>(); + Map<String, List<ArtifactDefinition>> groupToDelete = new HashMap<String, List<ArtifactDefinition>>(); + Map<String, List<String>> dissocArtifactFromGroup = new HashMap<String, List<String>>(); + + Set<ArtifactTemplateInfo> jsonMasterArtifacts = parsedGroup.keySet(); + + Map<GroupDefinition, MergedArtifactInfo> mergedgroup = mergeGroupInUpdateFlow(groupArtifact, parsedGroup, artifactsToDelete, groupToDelete, jsonMasterArtifacts); + + // find artifacts to delete + for (Entry<String, List<ArtifactDefinition>> deleteGroup : groupToDelete.entrySet()) { + + List<ArtifactDefinition> artifacts = deleteGroup.getValue(); + for (ArtifactDefinition artifact : artifacts) { + findArtifactToDelete(parsedGroup, artifactsToDelete, deleteGroup.getKey(), artifact); + } + + } + + // Set<String> deletedArtifactsName = new HashSet<String>(); + Either<List<ArtifactDefinition>, ResponseFormat> deletedArtifactsEither = deleteArtifactsInUpdateCsarFlow(resource, user, shouldLock, inTransaction, artifactsToDelete, groupToDelete); + if (deletedArtifactsEither.isRight()) { + log.debug("Failed to delete artifacts. Status is {} ", deletedArtifactsEither.right().value()); + + return Either.right(deletedArtifactsEither.right().value()); + + } + List<ArtifactDefinition> deletedArtifacts = deletedArtifactsEither.left().value(); + + // need to update resource if we updated artifacts + if (deletedArtifacts != null && !deletedArtifacts.isEmpty()) { + for (ArtifactDefinition deletedArtifact : deletedArtifacts) { + ArtifactDefinition artToRemove = null; + for (ArtifactDefinition artFromResource : createdDeplymentArtifactsAfterDelete) { + if (deletedArtifact.getUniqueId().equalsIgnoreCase(artFromResource.getUniqueId())) { + artToRemove = artFromResource; + break; + } + } + if (artToRemove != null) + createdDeplymentArtifactsAfterDelete.remove(artToRemove); + + } + } + + ////////////// dissociate, associate or create + ////////////// artifacts//////////////////////////// + Either<Resource, ResponseFormat> assDissotiateEither = associateAndDissociateArtifactsToGroup(csarUUID, csar, resource, user, createdNewArtifacts, labelCounter, shouldLock, inTransaction, createdDeplymentArtifactsAfterDelete, + dissocArtifactFromGroup, mergedgroup, deletedArtifacts); + + if (assDissotiateEither.isRight()) { + log.debug("Failed to delete artifacts. Status is {} ", assDissotiateEither.right().value()); + + return Either.right(assDissotiateEither.right().value()); + + } + resource = assDissotiateEither.left().value(); + groups = resource.getGroups(); + List<GroupDefinition> groupToUpdate = new ArrayList<>(); + // update vfModule names + Set<GroupDefinition> groupForAssociateWithMembers = mergedgroup.keySet(); + if (groups != null && !groups.isEmpty()) { + Either<List<GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesRes = groupBusinessLogic.validateUpdateVfGroupNamesOnGraph(groups, resource.getSystemName(), inTransaction); + if (validateUpdateVfGroupNamesRes.isRight()) { + return Either.right(validateUpdateVfGroupNamesRes.right().value()); + } + List<GroupDefinition> heatGroups = null; + + // List<IArtifactInfo> collect = resources.stream().flatMap( e -> + // e.getArtifacts().stream()).filter(p -> + // relevantArtifactTypes.contains(p.getArtifactType() + // )).collect(Collectors.toList()); + // List<GroupDefinition> heatGroups = createdGroups.stream().filter( + // e -> e.getProperties().stream().filter(p -> + // p.getName().contains(Constants.HEAT_FILE_PROPS))).collect(Collectors.toList()); + heatGroups = groups.stream().filter(e -> e.getMembers() != null).collect(Collectors.toList()); + ; + + for (GroupDefinition updatedGroupDef : groupForAssociateWithMembers) { + GroupDefinition group = null; + Optional<GroupDefinition> opGr = groups.stream().filter(p -> p.getUniqueId().equals(updatedGroupDef.getUniqueId())).findAny(); + if (opGr.isPresent()) { + group = opGr.get(); + groupToUpdate.add(group); + } + if (group != null) { + Map<String, String> members = new HashMap<String, String>(); + Set<String> artifactsGroup = new HashSet<String>(); + artifactsGroup.addAll(group.getArtifacts()); + associateMembersTToArtifacts(createdNewArtifacts, createdDeplymentArtifactsAfterDelete, heatGroups, artifactsGroup, members); + if (!members.isEmpty()) { + group.setMembers(members); + + } + } + + } + if (!groupToUpdate.isEmpty()) { + Either<List<GroupDefinition>, ResponseFormat> assotiateGroupEither = groupBusinessLogic.associateMembersToGroup(resource.getUniqueId(), user.getUserId(), ComponentTypeEnum.RESOURCE, groupToUpdate, false, true); + if (assotiateGroupEither.isRight()) { + log.debug("Failed to associate artifacts to groups. Status is {} ", assotiateGroupEither.right().value()); + return Either.right(assotiateGroupEither.right().value()); + + } + } + + } + + //////////////// create new artifacts in update + //////////////// flow//////////////////////////// + List<ArtifactTemplateInfo> newArtifactsGroup = new ArrayList<ArtifactTemplateInfo>(); + + for (Entry<ArtifactTemplateInfo, Set<ArtifactTemplateInfo>> parsedGroupSetEntry : parsedGroup.entrySet()) { + ArtifactTemplateInfo parsedArtifactMaster = parsedGroupSetEntry.getKey(); + boolean isNewGroup = true; + for (Entry<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>> groupListEntry : groupArtifact.entrySet()) { + Map<ArtifactDefinition, List<ArtifactDefinition>> groupArtifacts = groupListEntry.getValue(); + Set<ArtifactDefinition> group = groupArtifacts.keySet(); + for (ArtifactDefinition artifactInfo : group) { + if (parsedArtifactMaster.getFileName().equalsIgnoreCase(artifactInfo.getArtifactName())) { + parsedArtifactMaster.setGroupName(groupListEntry.getKey().getName()); + isNewGroup = false; + } + } + } + if (isNewGroup) + newArtifactsGroup.add(parsedArtifactMaster); + + } + if (!newArtifactsGroup.isEmpty()) { + Collections.sort(newArtifactsGroup, (art1, art2) -> ArtifactTemplateInfo.compareByGroupName(art1, art2)); + int startGroupCounter = groupBusinessLogic.getNextVfModuleNameCounter(groups); + Either<Boolean, ResponseFormat> validateGroupNamesRes = groupBusinessLogic.validateGenerateVfModuleGroupNames(newArtifactsGroup, resource.getSystemName(), startGroupCounter); + if (validateGroupNamesRes.isRight()) { + return Either.right(validateGroupNamesRes.right().value()); + } + Either<Resource, ResponseFormat> resStatus = createGroupDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, newArtifactsGroup, createdNewArtifacts, createdDeplymentArtifactsAfterDelete, labelCounter, shouldLock, inTransaction); + if (resStatus.isRight()) + return resStatus; + } + + // updatedGroup + if (!groupForAssociateWithMembers.isEmpty()) { + + List<String> groupsId = groupForAssociateWithMembers.stream().map(e -> e.getUniqueId()).collect(Collectors.toList()); + + Either<List<GroupDefinition>, StorageOperationStatus> updateVersionEither = groupBusinessLogic.updateGroupVersion(groupsId, true); + if (updateVersionEither.isRight()) { + log.debug("Failed to update groups version. Status is {} ", updateVersionEither.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(updateVersionEither.right().value()), resource); + return Either.right(responseFormat); + + } + } + + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getResource(resource.getUniqueId(), inTransaction); + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + return Either.right(responseFormat); + + } + return Either.left(eitherGerResource.left().value()); + + } + + private Either<List<ArtifactDefinition>, ResponseFormat> deleteArtifactsInUpdateCsarFlow(Resource resource, User user, boolean shouldLock, boolean inTransaction, Set<ArtifactDefinition> artifactsToDelete, + Map<String, List<ArtifactDefinition>> groupToDelete) { + List<ArtifactDefinition> deletedArtifacts = new ArrayList<ArtifactDefinition>(); + + if (!artifactsToDelete.isEmpty()) { + for (ArtifactDefinition artifact : artifactsToDelete) { + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> handleDelete = artifactsBusinessLogic.handleDelete(resource.getUniqueId(), artifact.getUniqueId(), user, AuditingActionEnum.ARTIFACT_DELETE, ComponentTypeEnum.RESOURCE, + resource, null, null, shouldLock, inTransaction); + if (handleDelete.isRight()) { + return Either.right(handleDelete.right().value()); + } + deletedArtifacts.add(handleDelete.left().value().left().value()); + + } + } + if (!groupToDelete.isEmpty()) { + log.debug("try to delete group"); + for (Entry<String, List<ArtifactDefinition>> deleteGroup : groupToDelete.entrySet()) { + Either<GroupDefinition, StorageOperationStatus> deleteGroupEither = groupOperation.deleteGroup(deleteGroup.getKey(), inTransaction); + if (deleteGroupEither.isRight()) { + StorageOperationStatus storageOperationStatus = deleteGroupEither.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus); + log.debug("Failed to delete group {} under component {}, error: {}", deleteGroup.getKey(), resource.getNormalizedName(), actionStatus.name()); + + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + + } + } + } + return Either.left(deletedArtifacts); + } + + private Either<Resource, ResponseFormat> associateAndDissociateArtifactsToGroup(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, List<ArtifactDefinition> createdNewArtifacts, int labelCounter, boolean shouldLock, + boolean inTransaction, List<ArtifactDefinition> createdDeplymentArtifactsAfterDelete, Map<String, List<String>> dissocArtifactFromGroup, Map<GroupDefinition, MergedArtifactInfo> mergedgroup, List<ArtifactDefinition> deletedArtifacts) { + Map<GroupDefinition, List<ArtifactTemplateInfo>> artifactsToAssotiate = new HashMap<GroupDefinition, List<ArtifactTemplateInfo>>(); + Map<GroupDefinition, List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>>> artifactsToUpdateMap = new HashMap<GroupDefinition, List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>>>(); + Either<Resource, ResponseFormat> resEither = Either.left(resource); + for (Entry<GroupDefinition, MergedArtifactInfo> entry : mergedgroup.entrySet()) { + List<ArtifactDefinition> dissArtifactsInGroup = entry.getValue().getListToDissotiateArtifactFromGroup(deletedArtifacts); + if (dissArtifactsInGroup != null && !dissArtifactsInGroup.isEmpty()) { + List<String> dissList = new ArrayList<String>(); + for (ArtifactDefinition art : dissArtifactsInGroup) { + dissList.add(art.getUniqueId()); + } + dissocArtifactFromGroup.put(entry.getKey().getUniqueId(), dissList); + } + + List<ArtifactTemplateInfo> newArtifactsInGroup = entry.getValue().getListToAssociateArtifactToGroup(); + if (newArtifactsInGroup != null && !newArtifactsInGroup.isEmpty()) + artifactsToAssotiate.put(entry.getKey(), newArtifactsInGroup); + + List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>> artifactsToUpdate = entry.getValue().getListToUpdateArtifactInGroup(); + if (artifactsToUpdate != null && !artifactsToUpdate.isEmpty()) + artifactsToUpdateMap.put(entry.getKey(), artifactsToUpdate); + } + + // Map<String, Set<String>> dissocArtifactFromGroup = new + // HashMap<String, Set<String>>(); + List<GroupDefinition> dissotiateArtifactsgroups = new ArrayList<GroupDefinition>(); + for (Entry<String, List<String>> dissotiateEntry : dissocArtifactFromGroup.entrySet()) { + + GroupDefinition dissotiateGroup = new GroupDefinition(); + dissotiateGroup.setUniqueId(dissotiateEntry.getKey()); + dissotiateGroup.setArtifacts(dissotiateEntry.getValue()); + dissotiateArtifactsgroups.add(dissotiateGroup); + } + if (!dissotiateArtifactsgroups.isEmpty()) { + log.debug("try to dissociate artifacts from groups "); + Either<List<GroupDefinition>, ResponseFormat> dissotiateGroupEither = groupBusinessLogic.dissociateArtifactsFromGroup(resource.getUniqueId(), user.getUserId(), ComponentTypeEnum.RESOURCE, dissotiateArtifactsgroups, shouldLock, + inTransaction); + if (dissotiateGroupEither.isRight()) { + log.debug("Failed to dissociate artifacts from groups. Status is {} ", dissotiateGroupEither.right().value()); + resEither = Either.right(dissotiateGroupEither.right().value()); + return resEither; + + } + } + + if (!artifactsToUpdateMap.isEmpty()) { + List<ArtifactDefinition> updatedArtifacts = new ArrayList<ArtifactDefinition>(); + for (Entry<GroupDefinition, List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>>> artifactsToUpdateEntry : artifactsToUpdateMap.entrySet()) { + List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>> artifactsToUpdateList = artifactsToUpdateEntry.getValue(); + for (ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo> artifact : artifactsToUpdateList) { + Either<ArtifactDefinition, ResponseFormat> updateArtifactEither = updateDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, artifact.getKey(), artifact.getValue(), updatedArtifacts, + artifact.getRight().getRelatedArtifactsInfo(), shouldLock, inTransaction); + if (updateArtifactEither.isRight()) { + log.debug("failed to update artifacts. status is {}", updateArtifactEither.right().value()); + resEither = Either.right(updateArtifactEither.right().value()); + return resEither; + + } + + } + } + + } + + List<GroupDefinition> associateArtifactGroup = new ArrayList<GroupDefinition>(); + + for (Entry<GroupDefinition, List<ArtifactTemplateInfo>> associateEntry : artifactsToAssotiate.entrySet()) { + List<ArtifactTemplateInfo> associatedArtifact = associateEntry.getValue(); + Set<String> arifactsUids = new HashSet<String>(); + for (ArtifactTemplateInfo artifactTemplate : associatedArtifact) { // try + // to + // find + // artifact + // in + // resource + boolean isCreate = true; + for (ArtifactDefinition createdArtifact : createdDeplymentArtifactsAfterDelete) { + if (artifactTemplate.getFileName().equalsIgnoreCase(createdArtifact.getArtifactName())) { + arifactsUids.add(createdArtifact.getUniqueId()); + isCreate = false; + break; + } + + } + if (isCreate) { // check if already created + for (ArtifactDefinition createdNewArtifact : createdNewArtifacts) { + if (artifactTemplate.getFileName().equalsIgnoreCase(createdNewArtifact.getArtifactName())) { + arifactsUids.add(createdNewArtifact.getUniqueId()); + isCreate = false; + break; + } + } + } + + if (isCreate) { + Either<ArtifactDefinition, ResponseFormat> createArtifactEither = createDeploymentArtifact(csarUUID, csar, resource, user, artifactTemplate, createdNewArtifacts, labelCounter, shouldLock, inTransaction); + if (createArtifactEither.isRight()) { + resEither = Either.right(createArtifactEither.right().value()); + return resEither; + } + arifactsUids.add(createArtifactEither.left().value().getUniqueId()); + } + + } + if (arifactsUids.size() > 0) { + List<String> artifactsToAssociate = new ArrayList<String>(); + artifactsToAssociate.addAll(arifactsUids); + GroupDefinition assotiateGroup = new GroupDefinition(); + assotiateGroup.setUniqueId(associateEntry.getKey().getUniqueId()); + assotiateGroup.setArtifacts(artifactsToAssociate); + associateArtifactGroup.add(assotiateGroup); + + } + } + + if (!associateArtifactGroup.isEmpty()) { + + log.debug("Try to associate artifacts to groups."); + + Either<List<GroupDefinition>, ResponseFormat> assotiateGroupEither = groupBusinessLogic.associateArtifactsToGroup(resource.getUniqueId(), user.getUserId(), ComponentTypeEnum.RESOURCE, associateArtifactGroup, shouldLock, inTransaction); + if (assotiateGroupEither.isRight()) { + log.debug("Failed to associate artifacts to groups. Status is {} ", assotiateGroupEither.right().value()); + resEither = Either.right(assotiateGroupEither.right().value()); + return resEither; + + } + } + + ComponentParametersView parametersView = new ComponentParametersView(); + parametersView.disableAll(); + parametersView.setIgnoreComponentInstances(false); + parametersView.setIgnoreUsers(false); + parametersView.setIgnoreArtifacts(false); + parametersView.setIgnoreGroups(false); + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getComponent(resource.getUniqueId(), parametersView, inTransaction); + + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + resEither = Either.right(responseFormat); + return resEither; + + } + resEither = Either.left(eitherGerResource.left().value()); + return resEither; + } + + private Map<GroupDefinition, MergedArtifactInfo> mergeGroupInUpdateFlow(Map<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>> groupArtifact, Map<ArtifactTemplateInfo, Set<ArtifactTemplateInfo>> parsedGroup, + Set<ArtifactDefinition> artifactsToDelete, Map<String, List<ArtifactDefinition>> groupToDelete, Set<ArtifactTemplateInfo> jsonMasterArtifacts) { + Map<GroupDefinition, MergedArtifactInfo> mergedgroup = new HashMap<GroupDefinition, MergedArtifactInfo>(); + for (Entry<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>> groupListEntry : groupArtifact.entrySet()) { + Map<ArtifactDefinition, List<ArtifactDefinition>> createdArtifactMap = groupListEntry.getValue(); + boolean isNeedToDeleteGroup = true; + List<ArtifactDefinition> listToDelete = null; + for (ArtifactDefinition maserArtifact : createdArtifactMap.keySet()) { + listToDelete = createdArtifactMap.get(maserArtifact); + for (ArtifactDefinition artToDelete : listToDelete) { + findArtifactToDelete(parsedGroup, artifactsToDelete, groupListEntry.getKey().getUniqueId(), artToDelete); + } + for (ArtifactTemplateInfo jsonMasterArtifact : jsonMasterArtifacts) { + if (maserArtifact.getArtifactName().equalsIgnoreCase(jsonMasterArtifact.getFileName())) { + MergedArtifactInfo mergedGroup = new MergedArtifactInfo(); + mergedGroup.setJsonArtifactTemplate(jsonMasterArtifact); + mergedGroup.setCreatedArtifact(createdArtifactMap.get(maserArtifact)); + mergedgroup.put(groupListEntry.getKey(), mergedGroup); + isNeedToDeleteGroup = false; + + } + } + + } + if (isNeedToDeleteGroup) { + groupToDelete.put(groupListEntry.getKey().getUniqueId(), listToDelete); + } + + } + return mergedgroup; + } + + private Set<String> findArtifactsNotInGroupToDelete(List<GroupDefinition> groups, List<ArtifactDefinition> createdDeplymentArtifactsAfterDelete) { + Set<String> artifactNotInGroupSet = new HashSet<String>(); + for (ArtifactDefinition artifact : createdDeplymentArtifactsAfterDelete) { + boolean needToDelete = true; + if (artifact.getArtifactName().equalsIgnoreCase(Constants.VENDOR_LICENSE_MODEL) || artifact.getArtifactName().equalsIgnoreCase(Constants.VF_LICENSE_MODEL)) + continue; + if (groups != null) { + for (GroupDefinition group : groups) { + List<String> groupArtifactIds = group.getArtifacts(); + if (groupArtifactIds == null || groupArtifactIds.isEmpty()) { + continue; + } + for (String groupArtifactid : groupArtifactIds) { + if (groupArtifactid.equalsIgnoreCase(artifact.getUniqueId())) + needToDelete = false; + + } + + } + } + if (needToDelete) + artifactNotInGroupSet.add(artifact.getUniqueId()); + } + return artifactNotInGroupSet; + } + + private void findArtifactToDelete(Map<ArtifactTemplateInfo, Set<ArtifactTemplateInfo>> parsedGroup, Set<ArtifactDefinition> artifactsToDelete, String deleteGroupId, ArtifactDefinition artifact) { + boolean isNeedToDeleteArtifact = true; + for (Entry<ArtifactTemplateInfo, Set<ArtifactTemplateInfo>> parsedGroupSetEntry : parsedGroup.entrySet()) { + Set<ArtifactTemplateInfo> artifactsNames = parsedGroupSetEntry.getValue(); + for (ArtifactTemplateInfo template : artifactsNames) { + if (artifact.getArtifactName().equalsIgnoreCase(template.getFileName()) && artifact.getArtifactType().equalsIgnoreCase(template.getType())) { + isNeedToDeleteArtifact = false; + + } + } + } + if (isNeedToDeleteArtifact) { + + artifactsToDelete.add(artifact); + + } + } + + private Map<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>> findMasterArtifactInGroup(List<GroupDefinition> groups, Map<String, ArtifactDefinition> deplymentArtifact) { + Map<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>> groupArtifact = new HashMap<GroupDefinition, Map<ArtifactDefinition, List<ArtifactDefinition>>>(); + + for (GroupDefinition group : groups) { + Map<ArtifactDefinition, List<ArtifactDefinition>> gupsMap = new HashMap<ArtifactDefinition, List<ArtifactDefinition>>(); + List<ArtifactDefinition> artifacts = new ArrayList<ArtifactDefinition>(); + List<String> artifactsList = group.getArtifacts(); + if (artifactsList != null && !artifactsList.isEmpty()) { + + ArtifactDefinition masterArtifact = ArtifactUtils.findMasterArtifact(deplymentArtifact, artifacts, artifactsList); + if (masterArtifact != null) + gupsMap.put(masterArtifact, artifacts); + groupArtifact.put(group, gupsMap); + + } + } + return groupArtifact; + } + + private void createArtifactsGroupSet(List<ArtifactTemplateInfo> parsedGroupTemplateList, Set<ArtifactTemplateInfo> parsedArtifactsName) { + + for (ArtifactTemplateInfo parsedGroupTemplate : parsedGroupTemplateList) { + parsedArtifactsName.add(parsedGroupTemplate); + List<ArtifactTemplateInfo> relatedArtifacts = parsedGroupTemplate.getRelatedArtifactsInfo(); + if (relatedArtifacts != null && !relatedArtifacts.isEmpty()) { + createArtifactsGroupSet(relatedArtifacts, parsedArtifactsName); + } + } + } + + public Either<Resource, ResponseFormat> createResourceArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, String artifactsMetaFile, String artifactsMetaFileName, List<ArtifactDefinition> createdArtifacts, + boolean shouldLock, boolean inTransaction) { + + log.debug("parseResourceArtifactsInfoFromFile start"); + Either<Map<String, List<ArtifactTemplateInfo>>, ResponseFormat> parseResourceInfoFromYamlEither = parseResourceArtifactsInfoFromFile(resource, artifactsMetaFile, artifactsMetaFileName, user); + if (parseResourceInfoFromYamlEither.isRight()) { + ResponseFormat responseFormat = parseResourceInfoFromYamlEither.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return Either.right(responseFormat); + } + log.debug("parseResourceArtifactsInfoFromFile end"); + + log.debug("createResourceArtifacts start"); + Either<Resource, ResponseFormat> respStatus = createResourceArtifacts(csarUUID, csar, resource, user, parseResourceInfoFromYamlEither.left().value(), AuditingActionEnum.CREATE_RESOURCE, createdArtifacts, shouldLock, inTransaction); + if (respStatus.isRight()) { + return respStatus; + } + log.debug("createResourceArtifacts end"); + log.debug("getResource start"); + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getResource(resource.getUniqueId(), inTransaction); + log.debug("getResource end"); + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + return Either.right(responseFormat); + + } + return Either.left(eitherGerResource.left().value()); + + } + + private Either<Resource, ResponseFormat> createGroupDeploymentArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, List<ArtifactTemplateInfo> artifactsTemplateList, + List<ArtifactDefinition> createdNewArtifacts, List<ArtifactDefinition> artifactsFromResource, int labelCounter, boolean shouldLock, boolean inTransaction) { + Either<Resource, ResponseFormat> resStatus = Either.left(resource); + List<GroupDefinition> createdGroups = resource.getGroups(); + List<GroupDefinition> heatGroups = null; + if (createdGroups != null && !createdGroups.isEmpty()) { + + // List<IArtifactInfo> collect = resources.stream().flatMap( e -> + // e.getArtifacts().stream()).filter(p -> + // relevantArtifactTypes.contains(p.getArtifactType() + // )).collect(Collectors.toList()); + // List<GroupDefinition> heatGroups = createdGroups.stream().filter( + // e -> e.getProperties().stream().filter(p -> + // p.getName().contains(Constants.HEAT_FILE_PROPS))).collect(Collectors.toList()); + heatGroups = createdGroups.stream().filter(e -> e.getMembers() != null).collect(Collectors.toList()); + ; + } + + for (ArtifactTemplateInfo groupTemplateInfo : artifactsTemplateList) { + String groupName = groupTemplateInfo.getGroupName(); + Set<String> artifactsGroup = new HashSet<String>(); + + resStatus = createDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, artifactsGroup, groupTemplateInfo, createdNewArtifacts, artifactsFromResource, labelCounter, shouldLock, inTransaction); + if (resStatus.isRight()) + return resStatus; + + Map<String, String> members = new HashMap<String, String>(); + associateMembersTToArtifacts(createdNewArtifacts, artifactsFromResource, heatGroups, artifactsGroup, members); + + List<String> artifactsList = new ArrayList<String>(artifactsGroup); + + GroupDefinition groupDefinition = new GroupDefinition(); + groupDefinition.setName(groupName); + groupDefinition.setType(Constants.DEFAULT_GROUP_VF_MODULE); + groupDefinition.setArtifacts(artifactsList); + if (!members.isEmpty()) + groupDefinition.setMembers(members); + + List<GroupProperty> properties = new ArrayList<GroupProperty>(); + GroupProperty prop = new GroupProperty(); + prop.setName(Constants.IS_BASE); + prop.setValue(Boolean.toString(groupTemplateInfo.isBase())); + + properties.add(prop); + groupDefinition.setProperties(properties); + Either<GroupDefinition, ResponseFormat> createGroup = groupBusinessLogic.createGroup(resource.getUniqueId(), user.getUserId(), ComponentTypeEnum.RESOURCE, groupDefinition, inTransaction); + if (createGroup.isRight()) + return Either.right(createGroup.right().value()); + + } + return resStatus; + } + + private Either<Resource, ResponseFormat> createDeploymentArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, Set<String> artifactsGroup, ArtifactTemplateInfo artifactTemplateInfo, + List<ArtifactDefinition> createdArtifacts, List<ArtifactDefinition> artifactsFromResource, int labelCounter, boolean shoudLock, boolean inTransaction) { + Either<Resource, ResponseFormat> resStatus = Either.left(resource); + String artifactFileName = artifactTemplateInfo.getFileName(); + String artifactUid = ""; + boolean alreadyExist = false; + + // check if artifacts already exist + if (artifactsFromResource != null && !artifactsFromResource.isEmpty()) { + for (ArtifactDefinition artifactFromResource : artifactsFromResource) { + if (artifactFromResource.getArtifactName().equals(artifactFileName)) { + artifactUid = artifactFromResource.getUniqueId(); + if (!artifactFromResource.getArtifactType().equalsIgnoreCase(artifactTemplateInfo.getType())) { + log.debug("Artifact with name {} and type {} already exist with type {}", artifactFileName, artifactTemplateInfo.getType(), artifactFromResource.getArtifactType()); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected formatr, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR, artifactFileName, artifactTemplateInfo.getType(), artifactFromResource.getArtifactType())); + } + alreadyExist = true; + break; + } + + } + + } + if (!alreadyExist) { + for (ArtifactDefinition createdArtifact : createdArtifacts) { + if (createdArtifact.getArtifactName().equals(artifactFileName)) { + artifactUid = createdArtifact.getUniqueId(); + if (!createdArtifact.getArtifactType().equalsIgnoreCase(artifactTemplateInfo.getType())) { + log.debug("Artifact with name {} and type {} already exist with type {}", artifactFileName, artifactTemplateInfo.getType(), createdArtifact.getArtifactType()); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected formatr, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR, artifactFileName, artifactTemplateInfo.getType(), createdArtifact.getArtifactType())); + } + alreadyExist = true; + break; + } + + } + } + // if not exist need to create + if (!alreadyExist) { + + Either<ArtifactDefinition, ResponseFormat> newArtifactEither = createDeploymentArtifact(csarUUID, csar, resource, user, artifactTemplateInfo, createdArtifacts, labelCounter, shoudLock, inTransaction); + if (newArtifactEither.isRight()) { + resStatus = Either.right(newArtifactEither.right().value()); + return resStatus; + } + artifactUid = newArtifactEither.left().value().getUniqueId(); + + } + + artifactsGroup.add(artifactUid); + + List<ArtifactTemplateInfo> relatedArtifacts = artifactTemplateInfo.getRelatedArtifactsInfo(); + if (relatedArtifacts != null) { + for (ArtifactTemplateInfo relatedArtifactTemplateInfo : relatedArtifacts) { + resStatus = createDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, artifactsGroup, relatedArtifactTemplateInfo, createdArtifacts, artifactsFromResource, labelCounter, shoudLock, inTransaction); + if (resStatus.isRight()) + return resStatus; + } + } + return resStatus; + } + + private Either<Resource, ResponseFormat> createResourceArtifacts(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, Map<String, List<ArtifactTemplateInfo>> artifactsMap, AuditingActionEnum createResource, + List<ArtifactDefinition> createdArtifacts, boolean shouldLock, boolean inTransaction) { + + Either<Resource, ResponseFormat> resStatus = Either.left(resource); + + Collection<List<ArtifactTemplateInfo>> arifactsCollection = artifactsMap.values(); + + for (List<ArtifactTemplateInfo> groupTemplateList : arifactsCollection) { + if (groupTemplateList != null) { + resStatus = createGroupDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, groupTemplateList, createdArtifacts, 0, shouldLock, inTransaction); + if (resStatus.isRight()) + return resStatus; + } + } + + return resStatus; + + } + + private Either<Resource, ResponseFormat> createGroupDeploymentArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, List<ArtifactTemplateInfo> artifactsTemplateList, List<ArtifactDefinition> createdArtifacts, + int labelCounter, boolean shouldLock, boolean inTransaction) { + Either<Resource, ResponseFormat> resStatus = Either.left(resource); + List<GroupDefinition> createdGroups = resource.getGroups(); + List<GroupDefinition> heatGroups = null; + if (createdGroups != null && !createdGroups.isEmpty()) { + + // List<IArtifactInfo> collect = resources.stream().flatMap( e -> + // e.getArtifacts().stream()).filter(p -> + // relevantArtifactTypes.contains(p.getArtifactType() + // )).collect(Collectors.toList()); + // List<GroupDefinition> heatGroups = createdGroups.stream().filter( + // e -> e.getProperties().stream().filter(p -> + // p.getName().contains(Constants.HEAT_FILE_PROPS))).collect(Collectors.toList()); + heatGroups = createdGroups.stream().filter(e -> e.getMembers() != null).collect(Collectors.toList()); + ; + } + for (ArtifactTemplateInfo groupTemplateInfo : artifactsTemplateList) { + String groupName = groupTemplateInfo.getGroupName(); + Set<String> artifactsGroup = new HashSet<String>(); + + log.debug("createDeploymentArtifactsFromCsar start"); + resStatus = createDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, artifactsGroup, groupTemplateInfo, createdArtifacts, labelCounter, shouldLock, inTransaction); + log.debug("createDeploymentArtifactsFromCsar end"); + if (resStatus.isRight()) + return resStatus; + + Map<String, String> members = new HashMap<String, String>(); + associateMembersTToArtifacts(createdArtifacts, null, heatGroups, artifactsGroup, members); + + List<String> artifactsList = new ArrayList<String>(artifactsGroup); + + GroupDefinition groupDefinition = new GroupDefinition(); + groupDefinition.setName(groupName); + groupDefinition.setType(Constants.DEFAULT_GROUP_VF_MODULE); + groupDefinition.setArtifacts(artifactsList); + if (!members.isEmpty()) + groupDefinition.setMembers(members); + List<GroupProperty> properties = new ArrayList<GroupProperty>(); + GroupProperty prop = new GroupProperty(); + prop.setName(Constants.IS_BASE); + prop.setValue(Boolean.toString(groupTemplateInfo.isBase())); + + properties.add(prop); + groupDefinition.setProperties(properties); + log.debug("createGroup start"); + // Either<GroupDefinition, ResponseFormat> createGroup = + // groupBusinessLogic.createGroup(resource.getUniqueId(), + // user.getUserId(), ComponentTypeEnum.RESOURCE, groupDefinition, + // inTransaction); + // Ignore validations and get component + + // Since in these groups we handle only artifacts, then no need to + // fetch component instances + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreArtifacts(false); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreComponentInstances(false); + Either<Resource, StorageOperationStatus> component = resourceOperation.getComponent(resource.getUniqueId(), componentParametersView, inTransaction); + if (component.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + Either<GroupDefinition, ResponseFormat> createGroup = groupBusinessLogic.createGroup(component.left().value(), user, ComponentTypeEnum.RESOURCE, groupDefinition, inTransaction); + log.debug("createGroup end"); + if (createGroup.isRight()) + return Either.right(createGroup.right().value()); + + } + return resStatus; + } + + private void associateMembersTToArtifacts(List<ArtifactDefinition> createdArtifacts, List<ArtifactDefinition> artifactsFromResource, List<GroupDefinition> heatGroups, Set<String> artifactsGroup, Map<String, String> members) { + if (heatGroups != null && !heatGroups.isEmpty()) { + for (GroupDefinition heatGroup : heatGroups) { + List<GroupProperty> grpoupProps = heatGroup.getProperties(); + if (grpoupProps != null) { + Optional<GroupProperty> op = grpoupProps.stream().filter(p -> p.getName().equals(Constants.HEAT_FILE_PROPS)).findAny(); + if (op.isPresent()) { + GroupProperty prop = op.get(); + String heatFileNAme = prop.getValue(); + if (null == heatFileNAme || heatFileNAme.isEmpty()) + continue; + List<ArtifactDefinition> artifacts = new ArrayList(); + for (String artifactId : artifactsGroup) { + Optional<ArtifactDefinition> opArt = createdArtifacts.stream().filter(p -> p.getUniqueId().equals(artifactId)).findAny(); + if (opArt.isPresent()) { + artifacts.add(opArt.get()); + } + if (artifactsFromResource != null) { + opArt = artifactsFromResource.stream().filter(p -> p.getUniqueId().equals(artifactId)).findAny(); + if (opArt.isPresent()) { + artifacts.add(opArt.get()); + } + } + } + Optional<ArtifactDefinition> resOp = artifacts.stream().filter(p -> heatFileNAme.contains(p.getArtifactName())).findAny(); + if (resOp.isPresent()) { + members.putAll(heatGroup.getMembers()); + } + } + } + } + + } + } + + private Either<Resource, ResponseFormat> createDeploymentArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, Set<String> artifactsGroup, ArtifactTemplateInfo artifactTemplateInfo, + List<ArtifactDefinition> createdArtifacts, int labelCounter, boolean shoudLock, boolean inTransaction) { + Either<Resource, ResponseFormat> resStatus = Either.left(resource); + String artifactFileName = artifactTemplateInfo.getFileName(); + String artifactUid = ""; + boolean alreadyExist = false; + + // check if artifacts already exist + for (ArtifactDefinition createdArtifact : createdArtifacts) { + if (createdArtifact.getArtifactName().equals(artifactFileName)) { + artifactUid = createdArtifact.getUniqueId(); + if (!createdArtifact.getArtifactType().equalsIgnoreCase(artifactTemplateInfo.getType())) { + log.debug("Artifact with name {} and type {} already exist with type {}", artifactFileName, artifactTemplateInfo.getType(), createdArtifact.getArtifactType()); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected formatr, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR, artifactFileName, artifactTemplateInfo.getType(), createdArtifact.getArtifactType())); + } + alreadyExist = true; + break; + } + + } + // if not exist need to create + if (!alreadyExist) { + + Either<ArtifactDefinition, ResponseFormat> newArtifactEither = createDeploymentArtifact(csarUUID, csar, resource, user, artifactTemplateInfo, createdArtifacts, labelCounter, shoudLock, inTransaction); + if (newArtifactEither.isRight()) { + resStatus = Either.right(newArtifactEither.right().value()); + return resStatus; + } + artifactUid = newArtifactEither.left().value().getUniqueId(); + + } + + artifactsGroup.add(artifactUid); + + List<ArtifactTemplateInfo> relatedArtifacts = artifactTemplateInfo.getRelatedArtifactsInfo(); + if (relatedArtifacts != null) { + for (ArtifactTemplateInfo relatedArtifactTemplateInfo : relatedArtifacts) { + resStatus = createDeploymentArtifactsFromCsar(csarUUID, csar, resource, user, artifactsGroup, relatedArtifactTemplateInfo, createdArtifacts, labelCounter, shoudLock, inTransaction); + if (resStatus.isRight()) + return resStatus; + } + } + return resStatus; + } + + private Either<ArtifactDefinition, ResponseFormat> createDeploymentArtifact(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, ArtifactTemplateInfo artifactTemplateInfo, List<ArtifactDefinition> createdArtifacts, + int labelCounter, boolean shoudLock, boolean inTransaction) { + String artifactUid; + Either<ImmutablePair<String, byte[]>, ResponseFormat> artifactContententStatus = CsarValidationUtils.getArtifactsContent(csarUUID, csar, artifactTemplateInfo.getFileName(), componentsUtils); + if (artifactContententStatus.isRight()) + return Either.right(artifactContententStatus.right().value()); + labelCounter += createdArtifacts.size(); + + Map<String, Object> json = buildJsonForArtifact(artifactTemplateInfo, artifactContententStatus.left().value().getValue(), labelCounter); + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> uploadArtifactToService = createOrUpdateCsarArtifactFromJson(resource, user, json, ArtifactOperation.Create, shoudLock, inTransaction); + + if (uploadArtifactToService.isRight()) + return Either.right(uploadArtifactToService.right().value()); + + ArtifactDefinition currentInfo = uploadArtifactToService.left().value().left().value(); + if (currentInfo.getHeatParameters() != null) { + + Either<ArtifactDefinition, ResponseFormat> updateEnvEither = updateHeatParamsFromCsar(csarUUID, csar, artifactTemplateInfo, currentInfo); + if (updateEnvEither.isRight()) { + log.debug("failed to update parameters to artifact {}", artifactTemplateInfo.getFileName()); + return Either.right(updateEnvEither.right().value()); + + } + artifactUid = updateEnvEither.left().value().getUniqueId(); + createdArtifacts.add(updateEnvEither.left().value()); + currentInfo = updateEnvEither.left().value(); + } else { + + artifactUid = currentInfo.getUniqueId(); + createdArtifacts.add(currentInfo); + + } + return Either.left(currentInfo); + + } + + private Either<ArtifactDefinition, ResponseFormat> updateDeploymentArtifactsFromCsar(String csarUUID, Map<String, byte[]> csar, Resource resource, User user, ArtifactDefinition oldArtifact, ArtifactTemplateInfo artifactTemplateInfo, + List<ArtifactDefinition> updatedArtifacts, List<ArtifactTemplateInfo> updatedRequiredArtifacts, boolean shouldLock, boolean inTransaction) { + + Either<ArtifactDefinition, ResponseFormat> resStatus = null; + String artifactFileName = artifactTemplateInfo.getFileName(); + String artifactUid = ""; + + // check if artifacts already exist + for (ArtifactDefinition updatedArtifact : updatedArtifacts) { + if (updatedArtifact.getArtifactName().equals(artifactFileName)) { + artifactUid = updatedArtifact.getUniqueId(); + if (!updatedArtifact.getArtifactType().equalsIgnoreCase(artifactTemplateInfo.getType())) { + log.debug("Artifact with name {} and type {} already updated with type {}", artifactFileName, artifactTemplateInfo.getType(), updatedArtifact.getArtifactType()); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected formatr, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + resStatus = Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR, artifactFileName, artifactTemplateInfo.getType(), updatedArtifact.getArtifactType())); + return resStatus; + } + resStatus = Either.left(updatedArtifact); + return resStatus; + } + + } + + Either<ImmutablePair<String, byte[]>, ResponseFormat> artifactContententStatus = CsarValidationUtils.getArtifactsContent(csarUUID, csar, artifactTemplateInfo.getFileName(), componentsUtils); + if (artifactContententStatus.isRight()) { + resStatus = Either.right(artifactContententStatus.right().value()); + return resStatus; + } + + Map<String, Object> json = buildJsonForUpdateArtifact(oldArtifact.getUniqueId(), artifactFileName, oldArtifact.getArtifactType(), oldArtifact.getArtifactLabel(), oldArtifact.getArtifactDisplayName(), oldArtifact.getDescription(), + artifactContententStatus.left().value().getRight(), updatedRequiredArtifacts); + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> uploadArtifactToService = createOrUpdateCsarArtifactFromJson(resource, user, json, ArtifactOperation.Update, shouldLock, inTransaction); + + if (uploadArtifactToService.isRight()) { + resStatus = Either.right(uploadArtifactToService.right().value()); + return resStatus; + } + ArtifactDefinition currentInfo = uploadArtifactToService.left().value().left().value(); + + Either<ArtifactDefinition, ResponseFormat> updateEnvEither = updateHeatParamsFromCsar(csarUUID, csar, artifactTemplateInfo, currentInfo); + if (updateEnvEither.isRight()) { + log.debug("failed to update parameters to artifact {}", artifactFileName); + resStatus = Either.right(updateEnvEither.right().value()); + return resStatus; + } + + artifactUid = updateEnvEither.left().value().getUniqueId(); + updatedArtifacts.add(updateEnvEither.left().value()); + resStatus = Either.left(updateEnvEither.left().value()); + + return resStatus; + + } + + private Either<ArtifactDefinition, ResponseFormat> updateHeatParamsFromCsar(String csarUUID, Map<String, byte[]> csar, ArtifactTemplateInfo artifactTemplateInfo, ArtifactDefinition currentInfo) { + Either<ArtifactDefinition, ResponseFormat> resStatus = Either.left(currentInfo); + if (artifactTemplateInfo.getEnv() != null && !artifactTemplateInfo.getEnv().isEmpty()) { + + Either<ImmutablePair<String, byte[]>, ResponseFormat> artifactparamsStatus = CsarValidationUtils.getArtifactsContent(csarUUID, csar, artifactTemplateInfo.getEnv(), componentsUtils); + if (artifactparamsStatus.isRight()) { + resStatus = Either.right(artifactparamsStatus.right().value()); + return resStatus; + } + Either<List<HeatParameterDefinition>, ResponseFormat> propsStatus = extractHeatParameters(ArtifactTypeEnum.HEAT_ENV.getType(), artifactTemplateInfo.getEnv(), artifactparamsStatus.left().value().getValue()); + if (propsStatus.isRight()) { + + resStatus = Either.right(propsStatus.right().value()); + return resStatus; + } + List<HeatParameterDefinition> updatedHeatEnvParams = propsStatus.left().value(); + List<HeatParameterDefinition> currentHeatEnvParams = currentInfo.getHeatParameters(); + List<HeatParameterDefinition> newHeatEnvParams = new ArrayList<HeatParameterDefinition>(); + + if (updatedHeatEnvParams != null && !updatedHeatEnvParams.isEmpty() && currentHeatEnvParams != null && !currentHeatEnvParams.isEmpty()) { + + String paramName; + for (HeatParameterDefinition heatEnvParam : updatedHeatEnvParams) { + + paramName = heatEnvParam.getName(); + for (HeatParameterDefinition currHeatParam : currentHeatEnvParams) { + if (paramName.equalsIgnoreCase(currHeatParam.getName())) { + + String updatedParamValue = heatEnvParam.getCurrentValue(); + if (updatedParamValue == null) + updatedParamValue = heatEnvParam.getDefaultValue(); + HeatParameterType paramType = HeatParameterType.isValidType(currHeatParam.getType()); + if (!paramType.getValidator().isValid(updatedParamValue, null)) { + ActionStatus status = ActionStatus.INVALID_HEAT_PARAMETER_VALUE; + ResponseFormat responseFormat = componentsUtils.getResponseFormat(status, ArtifactTypeEnum.HEAT_ENV.getType(), paramType.getType(), paramName); + resStatus = Either.right(responseFormat); + return resStatus; + } + currHeatParam.setCurrentValue(paramType.getConverter().convert(updatedParamValue, null, null)); + newHeatEnvParams.add(currHeatParam); + break; + } + } + } + if (!newHeatEnvParams.isEmpty()) { + StorageOperationStatus operationStatus = heatParametersOperation.updateHeatParameters(currentHeatEnvParams); + + if (operationStatus != StorageOperationStatus.OK) { + log.debug("Failed to update artifact on graph - {}", currentInfo.getUniqueId()); + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(operationStatus)); + resStatus = Either.right(responseFormat); + return resStatus; + } + } + } + + } + return resStatus; + } + + private Either<List<HeatParameterDefinition>, ResponseFormat> extractHeatParameters(String artifactType, String fileName, byte[] content) { + // extract heat parameters + String heatDecodedPayload = GeneralUtility.isBase64Encoded(content) ? new String(Base64.decodeBase64(content)) : new String(content); + Either<List<HeatParameterDefinition>, ResultStatusEnum> heatParameters = ImportUtils.getHeatParamsWithoutImplicitTypes(heatDecodedPayload, artifactType); + if (heatParameters.isRight()) { + log.debug("File {} is not in expected key-value form in csar ", fileName); + BeEcompErrorManager.getInstance().logInternalDataError("File " + fileName + " is not in expected key-value form in csar ", "CSAR internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT, fileName)); + + } + return Either.left(heatParameters.left().value()); + + } + + private Map<String, Object> buildJsonForArtifact(ArtifactTemplateInfo artifactTemplateInfo, byte[] artifactContentent, int atrifactLabelCounter) { + + Map<String, Object> json = new HashMap<String, Object>(); + String artifactName = artifactTemplateInfo.getFileName(); + + json.put(Constants.ARTIFACT_NAME, artifactTemplateInfo.getFileName()); + json.put(Constants.ARTIFACT_TYPE, artifactTemplateInfo.getType()); + json.put(Constants.ARTIFACT_DESCRIPTION, "created from csar"); + + /* + * DE250204 + * There is no need to check if base64 encoding. All files that are inside the CSAR are not encoded and need to encoded. The check for isBase64 is not in cases we get files with extension .cert or .key these files are base64 but if do not + * encode them again, when the user download them, the decoded file will return not the encoded file that was upload. + */ + // String encodedPayload = new String(artifactContentent); + // boolean isEncoded = GeneralUtility.isBase64Encoded(artifactContentent); + // if (!isEncoded) { + // log.debug("payload is encoded. perform decode"); + String encodedPayload = Base64.encodeBase64String(artifactContentent); + // } + json.put(Constants.ARTIFACT_PAYLOAD_DATA, encodedPayload); + String displayName = artifactName; + if (artifactName.lastIndexOf(".") > 0) + displayName = artifactName.substring(0, artifactName.lastIndexOf(".")); + json.put(Constants.ARTIFACT_DISPLAY_NAME, displayName); + String label = ValidationUtils.normalizeArtifactLabel(artifactTemplateInfo.getType() + atrifactLabelCounter); + json.put(Constants.ARTIFACT_LABEL, label); + json.put(Constants.ARTIFACT_GROUP_TYPE, ArtifactGroupTypeEnum.DEPLOYMENT.getType()); + List<ArtifactTemplateInfo> requiredArtifacts = artifactTemplateInfo.getRelatedArtifactsInfo(); + json.put(Constants.REQUIRED_ARTIFACTS, (requiredArtifacts == null || requiredArtifacts.isEmpty()) ? new ArrayList<>() + : requiredArtifacts.stream().filter(e -> e.getType().equals(ArtifactTypeEnum.HEAT_ARTIFACT.getType()) || e.getType().equals(ArtifactTypeEnum.HEAT_NESTED.getType())).map(e -> e.getFileName()).collect(Collectors.toList())); + return json; + } + + private Map<String, Object> buildJsonForUpdateArtifact(String artifactId, String artifactName, String artifactType, String label, String displayName, String description, byte[] artifactContentent, + List<ArtifactTemplateInfo> updatedRequiredArtifacts) { + + Map<String, Object> json = new HashMap<String, Object>(); + if (artifactId != null && !artifactId.isEmpty()) + json.put(Constants.ARTIFACT_ID, artifactId); + + json.put(Constants.ARTIFACT_NAME, artifactName); + json.put(Constants.ARTIFACT_TYPE, artifactType); + json.put(Constants.ARTIFACT_DESCRIPTION, description); + + String encodedPayload = new String(artifactContentent); + // DE250204 - need to encode all. + //boolean isEncoded = GeneralUtility.isBase64Encoded(artifactContentent); + //if (!isEncoded) { + log.debug("payload is encoded. perform decode"); + encodedPayload = Base64.encodeBase64String(artifactContentent); + //} + + json.put(Constants.ARTIFACT_PAYLOAD_DATA, encodedPayload); + json.put(Constants.ARTIFACT_DISPLAY_NAME, displayName); + json.put(Constants.ARTIFACT_LABEL, label); + json.put(Constants.ARTIFACT_GROUP_TYPE, ArtifactGroupTypeEnum.DEPLOYMENT.getType()); + json.put(Constants.REQUIRED_ARTIFACTS, (updatedRequiredArtifacts == null || updatedRequiredArtifacts.isEmpty()) ? new ArrayList<>() + : updatedRequiredArtifacts.stream().filter(e -> e.getType().equals(ArtifactTypeEnum.HEAT_ARTIFACT.getType()) || e.getType().equals(ArtifactTypeEnum.HEAT_NESTED.getType())).map(e -> e.getFileName()).collect(Collectors.toList())); + return json; + } + + private Either<Map<String, List<ArtifactTemplateInfo>>, ResponseFormat> parseResourceArtifactsInfoFromFile(Resource resource, String artifactsMetaFile, String artifactFileName, User user) { + + try { + JsonObject jsonElement = new JsonObject(); + jsonElement = gson.fromJson(artifactsMetaFile, jsonElement.getClass()); + + JsonElement importStructureElement = jsonElement.get(Constants.IMPORT_STRUCTURE); + if (importStructureElement == null || importStructureElement.isJsonNull()) { + log.debug("Artifact file is not in expected formatr, fileName {}", artifactFileName); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected formatr, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, artifactFileName)); + } + + Map<String, List<Map<String, Object>>> artifactTemplateMap = new HashMap<String, List<Map<String, Object>>>(); + artifactTemplateMap = componentsUtils.parseJsonToObject(importStructureElement.toString(), HashMap.class); + if (artifactTemplateMap.isEmpty()) { + log.debug("Artifact file is not in expected formatr, fileName {}", artifactFileName); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected formatr, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, artifactFileName)); + } + + Set<String> artifactsTypeKeys = artifactTemplateMap.keySet(); + Map<String, List<ArtifactTemplateInfo>> artifactsMap = new HashMap<String, List<ArtifactTemplateInfo>>(); + List<ArtifactTemplateInfo> allGroups = new ArrayList<>(); + for (String artifactsTypeKey : artifactsTypeKeys) { + + List<Map<String, Object>> o = artifactTemplateMap.get(artifactsTypeKey); + Either<List<ArtifactTemplateInfo>, ResponseFormat> artifactTemplateInfoListPairStatus = createArtifactTemplateInfoModule(artifactsTypeKey, o); + if (artifactTemplateInfoListPairStatus.isRight()) { + log.debug("Artifact file is not in expected formatr, fileName {}", artifactFileName); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected format, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(artifactTemplateInfoListPairStatus.right().value()); + } + List<ArtifactTemplateInfo> artifactTemplateInfoList = artifactTemplateInfoListPairStatus.left().value(); + if (artifactTemplateInfoList == null) { + log.debug("Artifact file is not in expected formatr, fileName {}", artifactFileName); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected format, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, artifactFileName)); + + } + allGroups.addAll(artifactTemplateInfoList); + artifactsMap.put(artifactsTypeKey, artifactTemplateInfoList); + } + int counter = groupBusinessLogic.getNextVfModuleNameCounter(resource.getGroups()); + Either<Boolean, ResponseFormat> validateGroupNamesRes = groupBusinessLogic.validateGenerateVfModuleGroupNames(allGroups, resource.getSystemName(), counter); + if (validateGroupNamesRes.isRight()) { + return Either.right(validateGroupNamesRes.right().value()); + } + return Either.left(artifactsMap); + } catch (Exception e) { + log.debug("Artifact file is not in expected format, fileName {}", artifactFileName); + log.debug("failed with exception.", e); + BeEcompErrorManager.getInstance().logInternalDataError("Artifact file is not in expected format, fileName " + artifactFileName, "Artifact internals are invalid", ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID_FORMAT, artifactFileName)); + } + + } + + private Either<List<ArtifactTemplateInfo>, ResponseFormat> createArtifactTemplateInfoModule(String artifactsTypeKey, List<Map<String, Object>> jsonObject) { + List<ArtifactTemplateInfo> artifactTemplateInfoList = new ArrayList<ArtifactTemplateInfo>(); + for (Map<String, Object> o : jsonObject) { + Either<ArtifactTemplateInfo, ResponseFormat> artifacttemplateInfoStatus = ArtifactTemplateInfo.createArtifactTemplateInfoFromJson(componentsUtils, artifactsTypeKey, o, artifactTemplateInfoList, null); + if (artifacttemplateInfoStatus.isRight()) { + return Either.right(artifacttemplateInfoStatus.right().value()); + } + + ArtifactTemplateInfo artifacttemplateInfo = artifacttemplateInfoStatus.left().value(); + if (artifacttemplateInfo != null) { + artifactTemplateInfoList.add(artifacttemplateInfo); + } + + } + return Either.left(artifactTemplateInfoList); + } + + private Either<Resource, ResponseFormat> createResourceInstancesRelations(User user, String yamlName, Resource resource, Map<String, UploadComponentInstanceInfo> uploadResInstancesMap, boolean inTransaction, boolean needLock) { + log.debug("createResourceInstancesRelations try to create relations "); + List<ComponentInstance> componentInstancesList = resource.getComponentInstances(); + if (uploadResInstancesMap == null) { + log.debug("UploadComponentInstanceInfo is empty, fileName {}", yamlName); + BeEcompErrorManager.getInstance().logInternalDataError("UploadComponentInstanceInfo is emty, fileName {}", yamlName, ErrorSeverity.ERROR); + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE, yamlName); + return Either.right(responseFormat); + } + + if (componentInstancesList == null || componentInstancesList.isEmpty()) { + log.debug("componentInstancesList is empty in resource {} ", resource.getUniqueId()); + BeEcompErrorManager.getInstance().logInternalDataError("componentInstancesList is empty in resource {} ", resource.getUniqueId(), ErrorSeverity.ERROR); + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE, yamlName); + return Either.right(responseFormat); + } + + Map<String, List<PropertyDefinition>> propertiesListPerResource = new HashMap<>(); + + long totalCreateRel = 0; + long totalCreatePropVal = 0; + Iterator<Entry<String, UploadComponentInstanceInfo>> nodesInfoValue = uploadResInstancesMap.entrySet().iterator(); + while (nodesInfoValue.hasNext()) { + Entry<String, UploadComponentInstanceInfo> uploadComponentInstanceInfoEntry = nodesInfoValue.next(); + UploadComponentInstanceInfo uploadComponentInstanceInfo = uploadComponentInstanceInfoEntry.getValue(); + + ComponentInstance currentCompInstance = null; + for (ComponentInstance compInstance : componentInstancesList) { + if (compInstance.getName().equals(uploadComponentInstanceInfo.getName())) { + currentCompInstance = compInstance; + break; + } + } + + if (currentCompInstance == null) { + log.debug("component instance with name {} in resource {} ", uploadComponentInstanceInfo.getName(), resource.getUniqueId()); + BeEcompErrorManager.getInstance().logInternalDataError("component instance with name " + uploadComponentInstanceInfo.getName() + " in resource {} ", resource.getUniqueId(), ErrorSeverity.ERROR); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE, yamlName); + return Either.right(responseFormat); + } + String resourceInstanceId = currentCompInstance.getUniqueId(); + + log.debug("************* addPropertyValuesToRi start"); + long startAddProperty = System.currentTimeMillis(); + + ResponseFormat addPropertiesValueToRiRes = addPropertyValuesToRi(uploadComponentInstanceInfo, resource, resourceInstanceId, currentCompInstance, yamlName, propertiesListPerResource); + log.debug("************* addPropertyValuesToRi end"); + totalCreatePropVal += (System.currentTimeMillis() - startAddProperty); + + if (addPropertiesValueToRiRes.getStatus() != 200) { + return Either.right(addPropertiesValueToRiRes); + } + Map<String, List<UploadReqInfo>> regMap = uploadComponentInstanceInfo.getRequirements(); + if (regMap == null) + continue; + Iterator<Entry<String, List<UploadReqInfo>>> nodesRegValue = regMap.entrySet().iterator(); + + long startAddRelation = System.currentTimeMillis(); + + while (nodesRegValue.hasNext()) { + Entry<String, List<UploadReqInfo>> nodesRegInfoEntry = nodesRegValue.next(); + + List<UploadReqInfo> uploadRegInfoList = nodesRegInfoEntry.getValue(); + for (UploadReqInfo uploadRegInfo : uploadRegInfoList) { + log.debug("Going to create relation {}", uploadRegInfo.getName()); + String regName = uploadRegInfo.getName(); + String nodeCapName = uploadRegInfo.getNode(); + RequirementCapabilityRelDef regCapRelDef = new RequirementCapabilityRelDef(); + regCapRelDef.setFromNode(resourceInstanceId); + log.debug("try to find available requirement {} ", regName); + Either<RequirementDefinition, ResponseFormat> eitherReqStatus = findAviableRequiremen(regName, yamlName, uploadComponentInstanceInfo, currentCompInstance); + if (eitherReqStatus.isRight()) { + log.debug("failed to find available requirement {} status is {}", regName, eitherReqStatus.right().value()); + return Either.right(eitherReqStatus.right().value()); + } + + RequirementDefinition validReq = eitherReqStatus.left().value(); + List<RequirementAndRelationshipPair> reqAndRelationshipPairList = regCapRelDef.getRelationships(); + if (reqAndRelationshipPairList == null) + reqAndRelationshipPairList = new ArrayList<RequirementAndRelationshipPair>(); + RequirementAndRelationshipPair reqAndRelationshipPair = new RequirementAndRelationshipPair(); + reqAndRelationshipPair.setRequirement(regName); + reqAndRelationshipPair.setRequirementOwnerId(validReq.getOwnerId()); + reqAndRelationshipPair.setRequirementUid(validReq.getUniqueId()); + + ComponentInstance currentCapCompInstance = null; + for (ComponentInstance compInstance : componentInstancesList) { + if (compInstance.getName().equals(uploadRegInfo.getNode())) { + currentCapCompInstance = compInstance; + break; + } + } + + if (currentCapCompInstance == null) { + log.debug("component instance with name {} in resource {} ", uploadRegInfo.getNode(), resource.getUniqueId()); + BeEcompErrorManager.getInstance().logInternalDataError("component instance with name " + uploadRegInfo.getNode() + " in resource {} ", resource.getUniqueId(), ErrorSeverity.ERROR); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE, yamlName); + return Either.right(responseFormat); + } + regCapRelDef.setToNode(currentCapCompInstance.getUniqueId()); + log.debug("try to find aviable Capability req name is {} ", validReq.getName()); + CapabilityDefinition aviableCapForRel = findAvailableCapabilityByTypeOrName(validReq, currentCapCompInstance, uploadRegInfo); + if (aviableCapForRel == null) { + log.debug("aviable capability was not found. req name is {} component instance is {}", validReq.getName(), currentCapCompInstance.getUniqueId()); + BeEcompErrorManager.getInstance().logInternalDataError("aviable capability was not found. req name is " + validReq.getName() + " component instance is " + currentCapCompInstance.getUniqueId(), resource.getUniqueId(), + ErrorSeverity.ERROR); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE, yamlName); + return Either.right(responseFormat); + } + reqAndRelationshipPair.setCapability(aviableCapForRel.getName()); + reqAndRelationshipPair.setCapabilityUid(aviableCapForRel.getUniqueId()); + reqAndRelationshipPair.setCapabilityOwnerId(aviableCapForRel.getOwnerId()); + reqAndRelationshipPairList.add(reqAndRelationshipPair); + regCapRelDef.setRelationships(reqAndRelationshipPairList); + ComponentInstanceBusinessLogic componentInstanceBL = getComponentInstanceBL(); + Either<RequirementCapabilityRelDef, ResponseFormat> eitherRelationRes = componentInstanceBL.associateRIToRIOnGraph(resource.getUniqueId(), regCapRelDef, ComponentTypeEnum.RESOURCE, inTransaction); + log.debug("************* finished to create relation {}", uploadRegInfo.getName()); + if (eitherRelationRes.isRight()) { + log.debug("failed to associate ri {} to ri {}", regCapRelDef.getFromNode(), regCapRelDef.getToNode()); + return Either.right(eitherRelationRes.right().value()); + } + + } + + } + totalCreateRel += (System.currentTimeMillis() - startAddRelation); + } + /* + * List<InputDefinition> inputs = resource.getInputs(); for(InputDefinition input: inputs){ if(input.getProperties() != null){ this.inputOperation.associatePropertiesToInputOnGraph(input. getUniqueId(), input.getProperties()); } } + */ + + // Either<Resource, StorageOperationStatus> eitherGerResource = + // resourceOperation.getResource(resource.getUniqueId(), inTransaction); + log.debug("************* create relations took : create {}, add property value {}", totalCreateRel, totalCreatePropVal); + log.debug("************* in create relations, getResource start"); + ComponentParametersView parametersView = new ComponentParametersView(); + parametersView.disableAll(); + parametersView.setIgnoreComponentInstances(false); + parametersView.setIgnoreUsers(false); + parametersView.setIgnoreArtifacts(false); + parametersView.setIgnoreGroups(false); + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getComponent(resource.getUniqueId(), parametersView, inTransaction); + log.debug("************* in create relations, getResource end"); + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + return Either.right(responseFormat); + + } + return Either.left(eitherGerResource.left().value()); + } + + private ResponseFormat addPropertyValuesToRi(UploadComponentInstanceInfo uploadComponentInstanceInfo, Resource resource, String resourceInstanceId, ComponentInstance currentCompInstance, String yamlName, + Map<String, List<PropertyDefinition>> propertiesListPerResource) { + + Map<String, List<UploadPropInfo>> propMap = uploadComponentInstanceInfo.getProperties(); + if (propMap != null && propMap.size() > 0) { + Map<String, PropertyDefinition> currPropertiesMap = new HashMap<String, PropertyDefinition>(); + List<PropertyDefinition> propertiesList = new ArrayList<PropertyDefinition>(); + Integer index = currentCompInstance.getPropertyValueCounter(); + Integer indexInput = currentCompInstance.getInputValueCounter(); + List<PropertyDefinition> listFromMap = propertiesListPerResource.get(currentCompInstance.getComponentUid()); + if (listFromMap != null) { + propertiesList = listFromMap; + } else { + TitanOperationStatus getPropertyRes = ((PropertyOperation) propertyOperation).findAllResourcePropertiesRecursively(currentCompInstance.getComponentUid(), propertiesList); + if (!getPropertyRes.equals(TitanOperationStatus.OK)) { + log.debug("failed to find properties of resource {} status is {}", currentCompInstance.getComponentUid(), getPropertyRes); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(getPropertyRes)), yamlName); + return responseFormat; + } + propertiesListPerResource.put(currentCompInstance.getComponentUid(), propertiesList); + } + if (propertiesList.size() > 0) { + for (PropertyDefinition prop : propertiesList) { + String propName = prop.getName(); + if (!currPropertiesMap.containsKey(propName)) { + currPropertiesMap.put(propName, prop); + } + } + for (List<UploadPropInfo> propertyList : propMap.values()) { + UploadPropInfo propertyInfo = propertyList.get(0); + String propName = propertyInfo.getName(); + if (!currPropertiesMap.containsKey(propName)) { + log.debug("failed to find property {} ", propName); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, propName); + return responseFormat; + } + PropertyDefinition curPropertyDef = currPropertiesMap.get(propName); + ComponentInstanceProperty property = null; + ComponentInstanceInput inputValue = null; + // TODO + String value = null; + List<GetInputValueInfo> getInputs = null; + boolean isValidate = true; + if (propertyInfo.getValue() != null) { + getInputs = propertyInfo.getGet_input(); + isValidate = getInputs == null || getInputs.isEmpty(); + if (isValidate) { + value = ImportUtils.getPropertyJsonStringValue(propertyInfo.getValue(), curPropertyDef.getType()); + } else + value = ImportUtils.getPropertyJsonStringValue(propertyInfo.getValue(), ToscaTagNamesEnum.GET_INPUT.getElementName()); + } + + property = new ComponentInstanceProperty(curPropertyDef, value, null); + + Either<ComponentInstanceProperty, StorageOperationStatus> result = componentInstanceOperation.addPropertyValueToResourceInstance(property, resourceInstanceId, isValidate, index, true); + if (result.isRight()) { + log.debug("Failed to add property value {} to resource instance {}", property, resourceInstanceId); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(result.right().value()); + return componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, currentCompInstance.getName()); + } + Either<Integer, StorageOperationStatus> increaseCounterRes = componentInstanceOperation.increaseAndGetResourceInstanceSpecificCounter(resourceInstanceId, GraphPropertiesDictionary.PROPERTY_COUNTER, true); + if (increaseCounterRes.isRight()) { + log.debug("Failed to increase resource property counter {} to resource instance {}", property, resourceInstanceId); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(increaseCounterRes.right().value()); + return componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, currentCompInstance.getName()); + } + index = increaseCounterRes.left().value(); + if (getInputs != null && !getInputs.isEmpty()) { + for (GetInputValueInfo getInput : getInputs) { + List<InputDefinition> inputs = resource.getInputs(); + if (inputs == null || inputs.isEmpty()) { + log.debug("Failed to add property {} to resource instance {}. Inputs list is empty ", property, resourceInstanceId); + return componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + } + + Optional<InputDefinition> optional = inputs.stream().filter(p -> p.getName().equals(getInput.getInputName())).findAny(); + if (!optional.isPresent()) { + log.debug("Failed to find input {} ", getInput.getInputName()); + // @@TODO error message + return componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + } + InputDefinition input = optional.get(); + TitanOperationStatus status = inputOperation.associatePropertyToInput(resourceInstanceId, input.getUniqueId(), result.left().value(), getInput); + if (status != TitanOperationStatus.OK) { + log.debug("Failed to associate input {} tp property value{} ", getInput.getInputName(), result.left().value().getValueUniqueUid()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(status)), yamlName); + return responseFormat; + } + GetInputValueInfo getInputIndex = getInput.getGetInputIndex(); + if (getInputIndex != null) { + optional = inputs.stream().filter(p -> p.getName().equals(getInputIndex.getInputName())).findAny(); + if (!optional.isPresent()) { + log.debug("Failed to find input {} ", getInputIndex.getInputName()); + // @@TODO error message + return componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + } + InputDefinition inputIndex = optional.get(); + status = inputOperation.associatePropertyToInput(resourceInstanceId, inputIndex.getUniqueId(), result.left().value(), getInputIndex); + if (status != TitanOperationStatus.OK) { + log.debug("Failed to associate input {} tp property value{} ", getInput.getInputName(), result.left().value().getValueUniqueUid()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(status)), yamlName); + return responseFormat; + } + + } + + } + } + + } + } + } + return componentsUtils.getResponseFormat(ActionStatus.OK); + } + + // US740820 Relate RIs according to capability name + private CapabilityDefinition findAvailableCapabilityByTypeOrName(RequirementDefinition validReq, ComponentInstance currentCapCompInstance, UploadReqInfo uploadReqInfo) { + if (null == uploadReqInfo.getCapabilityName() || validReq.getCapability().equals(uploadReqInfo.getCapabilityName())) {// get + // by + // capability + // type + return findAviableCapability(validReq, currentCapCompInstance); + } + return findAvailableCapability(validReq, currentCapCompInstance, uploadReqInfo); + } + + private CapabilityDefinition findAvailableCapability(RequirementDefinition validReq, ComponentInstance currentCapCompInstance, UploadReqInfo uploadReqInfo) { + Map<String, List<CapabilityDefinition>> capMap = currentCapCompInstance.getCapabilities(); + if (!capMap.containsKey(validReq.getCapability())) { + return null; + } + Optional<CapabilityDefinition> capByName = capMap.get(validReq.getCapability()).stream().filter(p -> p.getName().equals(uploadReqInfo.getCapabilityName())).findAny(); + if (!capByName.isPresent()) { + return null; + } + CapabilityDefinition cap = capByName.get(); + // TODO temporary fix - remove specific capability node validation - + // String reqNode = validReq.getNode(); + // if (reqNode != null && !reqNode.isEmpty() && + // !cap.getCapabilitySources().contains(reqNode)) { + // return null; + // } + RequirementAndRelationshipPair relationPair = getReqRelPair(cap); + Either<Boolean, StorageOperationStatus> eitherStatus = componentInstanceOperation.isAvailableCapabilty(currentCapCompInstance, relationPair); + if (eitherStatus.isRight() || eitherStatus.left().value() == false) { + return null; + } + return cap; + } + + private RequirementAndRelationshipPair getReqRelPair(CapabilityDefinition cap) { + RequirementAndRelationshipPair relationPair = new RequirementAndRelationshipPair(); + relationPair.setCapabilityUid(cap.getUniqueId()); + relationPair.setCapability(cap.getName()); + relationPair.setCapabilityOwnerId(cap.getOwnerId()); + return relationPair; + } + + private CapabilityDefinition findAviableCapability(RequirementDefinition validReq, ComponentInstance currentCapCompInstance) { + CapabilityDefinition aviableCapForRel = null; + Map<String, List<CapabilityDefinition>> capMap = currentCapCompInstance.getCapabilities(); + if (capMap.containsKey(validReq.getCapability())) { + List<CapabilityDefinition> capList = capMap.get(validReq.getCapability()); + + for (CapabilityDefinition cap : capList) { + // TODO temporary fix - remove specific capability node + // String reqNode = validReq.getNode(); + // if (reqNode != null && !reqNode.isEmpty()) { + // if (!cap.getCapabilitySources().contains(reqNode)) { + // continue; + // } + // } + + RequirementAndRelationshipPair relationPair = getReqRelPair(cap); + Either<Boolean, StorageOperationStatus> eitherStatus = componentInstanceOperation.isAvailableCapabilty(currentCapCompInstance, relationPair); + if (eitherStatus.isRight() || eitherStatus.left().value() == false) + continue; + else { + aviableCapForRel = cap; + break; + } + } + } + return aviableCapForRel; + } + + private Either<RequirementDefinition, ResponseFormat> findAviableRequiremen(String regName, String yamlName, UploadComponentInstanceInfo uploadComponentInstanceInfo, ComponentInstance currentCompInstance) { + Map<String, List<RequirementDefinition>> comInstRegDefMap = currentCompInstance.getRequirements(); + + Iterator<Entry<String, List<RequirementDefinition>>> regListValue = comInstRegDefMap.entrySet().iterator(); + RequirementDefinition validRegDef = null; + while (regListValue.hasNext()) { + Entry<String, List<RequirementDefinition>> regInfoEntry = regListValue.next(); + + List<RequirementDefinition> comInstRegDefList = regInfoEntry.getValue(); + + for (RequirementDefinition comInstRegDef : comInstRegDefList) { + if (!regName.equals(comInstRegDef.getName())) + continue; + RequirementAndRelationshipPair relationPair = new RequirementAndRelationshipPair(); + relationPair.setRequirementUid(comInstRegDef.getUniqueId()); + relationPair.setCapability(comInstRegDef.getCapability()); + relationPair.setRequirementOwnerId(comInstRegDef.getOwnerId()); + Either<Boolean, StorageOperationStatus> eitherStatus = componentInstanceOperation.isAvailableRequirement(currentCompInstance, relationPair); + if (eitherStatus.isLeft() && eitherStatus.left().value() == true) { + validRegDef = comInstRegDef; + break; + } + } + if (validRegDef != null) + break; + } + + if (validRegDef == null) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_NODE_TEMPLATE, yamlName, uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + return Either.right(responseFormat); + } + return Either.left(validRegDef); + } + + public Either<ParsedToscaYamlInfo, ResponseFormat> parseResourceInfoFromYaml(String yamlFileName, Resource resource, String resourceYml, User user) { + + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(resourceYml); + Either<Object, ResultStatusEnum> toscaElementEither = ImportUtils.findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.TOPOLOGY_TEMPLATE, ToscaElementTypeEnum.ALL); + if (toscaElementEither.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE); + return Either.right(responseFormat); + } + + Either<Map<String, InputDefinition>, ResponseFormat> createInputsEither = createInputsFromYaml(yamlFileName, mappedToscaTemplate, resource); + if (createInputsEither.isRight()) { + ResponseFormat responseFormat = createInputsEither.right().value(); + return Either.right(responseFormat); + } + + Either<Map<String, UploadComponentInstanceInfo>, ResponseFormat> uploadResInstancesEither = createResourcesInstanceInfoFromYaml(yamlFileName, mappedToscaTemplate, resource); + if (uploadResInstancesEither.isRight()) { + ResponseFormat responseFormat = uploadResInstancesEither.right().value(); + return Either.right(responseFormat); + } + + Either<Map<String, GroupDefinition>, ResponseFormat> createGroupsFromYaml = createGroupsFromYaml(yamlFileName, mappedToscaTemplate, resource); + if (createGroupsFromYaml.isRight()) { + ResponseFormat responseFormat = createGroupsFromYaml.right().value(); + return Either.right(responseFormat); + } + + ParsedToscaYamlInfo parsedToscaYamlInfo = new ParsedToscaYamlInfo(); + parsedToscaYamlInfo.setInputs(createInputsEither.left().value()); + parsedToscaYamlInfo.setInstances(uploadResInstancesEither.left().value()); + parsedToscaYamlInfo.setGroups(createGroupsFromYaml.left().value()); + + return Either.left(parsedToscaYamlInfo); + } + + private Either<Resource, ResponseFormat> createResourceInstances(User user, String yamlName, Resource resource, Map<String, UploadComponentInstanceInfo> uploadResInstancesMap, boolean inTransaction, boolean needLock, + Map<String, Resource> nodeTypeNamespaceMap) { + log.debug("createResourceInstances is {} - going to create resource instanse from CSAR", yamlName); + if (uploadResInstancesMap == null || uploadResInstancesMap.isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE); + + return Either.right(responseFormat); + + } + Map<String, Resource> existingnodeTypeMap = new HashMap<String, Resource>(); + if (nodeTypeNamespaceMap != null && !nodeTypeNamespaceMap.isEmpty()) { + nodeTypeNamespaceMap.entrySet().stream().forEach(x -> existingnodeTypeMap.put(x.getValue().getToscaResourceName(), x.getValue())); + } + + Iterator<Entry<String, UploadComponentInstanceInfo>> nodesInfoValue = uploadResInstancesMap.entrySet().iterator(); + while (nodesInfoValue.hasNext()) { + log.debug("*************Going to create resource instances {}", yamlName); + Entry<String, UploadComponentInstanceInfo> uploadComponentInstanceInfoEntry = nodesInfoValue.next(); + UploadComponentInstanceInfo uploadComponentInstanceInfo = uploadComponentInstanceInfoEntry.getValue(); + + // updating type if the type is node type name - we need to take the + // updated name + log.debug("*************Going to create resource instances {}", uploadComponentInstanceInfo.getName()); + if (nodeTypeNamespaceMap.containsKey(uploadComponentInstanceInfo.getType())) { + uploadComponentInstanceInfo.setType(nodeTypeNamespaceMap.get(uploadComponentInstanceInfo.getType()).getToscaResourceName()); + } + + Either<Resource, ResponseFormat> eitherResource = validateResourceInstanceBeforeCreate(yamlName, inTransaction, uploadComponentInstanceInfo, existingnodeTypeMap); + if (eitherResource.isRight()) { + return eitherResource; + } + Resource refResource = eitherResource.left().value(); + + ComponentInstance componentInstance = new ComponentInstance(); + + componentInstance.setName(uploadComponentInstanceInfo.getName()); + componentInstance.setComponentUid(refResource.getUniqueId()); + + ComponentTypeEnum containerComponentType = resource.getComponentType(); + NodeTypeEnum containerNodeType = containerComponentType.getNodeType(); + + if (containerNodeType.equals(NodeTypeEnum.Resource) && uploadComponentInstanceInfo.getCapabilities() != null) { + Either<Map<String, List<CapabilityDefinition>>, ResponseFormat> getValidComponentInstanceCapabilitiesRes = getValidComponentInstanceCapabilities(refResource.getCapabilities(), uploadComponentInstanceInfo.getCapabilities()); + if (getValidComponentInstanceCapabilitiesRes.isRight()) { + return Either.right(getValidComponentInstanceCapabilitiesRes.right().value()); + } else { + componentInstance.setCapabilities(getValidComponentInstanceCapabilitiesRes.left().value()); + } + } + if (!existingnodeTypeMap.containsKey(uploadComponentInstanceInfo.getType())) { + log.debug("createResourceInstances - not found lates version for resource instance with name {} and type ", uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_NODE_TEMPLATE, yamlName, uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + return Either.right(responseFormat); + } + Resource origResource = existingnodeTypeMap.get(uploadComponentInstanceInfo.getType()); + ComponentInstanceBusinessLogic componentInstanceBL = getComponentInstanceBL(); + Either<ComponentInstance, ResponseFormat> eitherCreateCI = componentInstanceBL.createComponentInstanceOnGraph(ComponentTypeEnum.RESOURCE_PARAM_NAME, resource, origResource, componentInstance, user.getUserId(), needLock, inTransaction); + if (eitherCreateCI.isRight()) { + log.debug("createResourceInstances - failed to create resource instance with name {} and type ", uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + return Either.right(eitherCreateCI.right().value()); + } + + ComponentInstance createdCI = eitherCreateCI.left().value(); + createdCI.setName(uploadComponentInstanceInfo.getName()); + /* + * updateComponentInstance(String containerComponentParam, org.openecomp.sdc.be.model.Component containerComponent, String componentInstanceId, ComponentInstance componentInstance, boolean inTransaction, boolean needLock) + */ + eitherCreateCI = componentInstanceBL.updateComponentInstance(ComponentTypeEnum.RESOURCE_PARAM_NAME, resource, origResource, createdCI.getUniqueId(), createdCI, needLock, inTransaction); + if (eitherCreateCI.isRight()) { + log.debug("createResourceInstances - failed to update resource instance with name {} and type ", uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + return Either.right(eitherCreateCI.right().value()); + } + log.debug("*************finished to create and update resource instances {}", uploadComponentInstanceInfo.getName()); + + } + log.debug("*************Going to get resource {}", resource.getUniqueId()); + ComponentParametersView parametersView = new ComponentParametersView(); + parametersView.disableAll(); + parametersView.setIgnoreComponentInstances(false); + parametersView.setIgnoreUsers(false); + parametersView.setIgnoreInputs(false); // inputs are read when creating + // property values on instances + Either<Resource, StorageOperationStatus> eitherGerResource = resourceOperation.getComponent(resource.getUniqueId(), parametersView, inTransaction); + log.debug("*************finished to get resource {}", resource.getUniqueId()); + if (eitherGerResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherGerResource.right().value()), resource); + + return Either.right(responseFormat); + + } + + if (eitherGerResource.left().value().getComponentInstances() == null || eitherGerResource.left().value().getComponentInstances().isEmpty()) { + + log.debug("Error when create resource inctanse from csar. ComponentInstances list empty"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Error when create resource inctanse from csar. ComponentInstances list empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE); + return Either.right(responseFormat); + + } + + return Either.left(eitherGerResource.left().value()); + } + + private Either<Resource, ResponseFormat> validateResourceInstanceBeforeCreate(String yamlName, boolean inTransaction, UploadComponentInstanceInfo uploadComponentInstanceInfo, Map<String, Resource> nodeTypeNamespaceMap) { + log.debug("validateResourceInstanceBeforeCreate - going to validate resource instance with name {} and type before create", uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + Resource refResource = null; + if (nodeTypeNamespaceMap.containsKey(uploadComponentInstanceInfo.getType())) { + refResource = nodeTypeNamespaceMap.get(uploadComponentInstanceInfo.getType()); + } else { + + Either<Boolean, StorageOperationStatus> eithervalidateResource = resourceOperation.validateToscaResourceNameExists(uploadComponentInstanceInfo.getType()); + if ((eithervalidateResource.isRight() && eithervalidateResource.right().value() == StorageOperationStatus.NOT_FOUND) || eithervalidateResource.left().value() == true) { + log.debug("validateResourceInstanceBeforeCreate - resource instance with name {} and type not valid", uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_NODE_TEMPLATE, yamlName, uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + return Either.right(responseFormat); + } + Either<Resource, StorageOperationStatus> findResourceEither = resourceOperation.getLatestCertifiedByToscaResourceName(uploadComponentInstanceInfo.getType(), inTransaction); + if (findResourceEither.isRight()) { + log.debug("validateResourceInstanceBeforeCreate - not found lates version for resource instance with name {} and type ", uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(findResourceEither.right().value())); + return Either.right(responseFormat); + } + refResource = findResourceEither.left().value(); + nodeTypeNamespaceMap.put(refResource.getToscaResourceName(), refResource); + } + String componentState = refResource.getComponentMetadataDefinition().getMetadataDataDefinition().getState(); + if (componentState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + log.debug("validateResourceInstanceBeforeCreate - component instance of component {} can not be created because the component is in an illegal state {}.", refResource.getName(), componentState); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.ILLEGAL_COMPONENT_STATE, refResource.getComponentType().getValue(), refResource.getName(), componentState); + return Either.right(responseFormat); + } + ResourceTypeEnum resourceTypeEnum = refResource.getResourceType(); + if (resourceTypeEnum == ResourceTypeEnum.VF) { + log.debug("validateResourceInstanceBeforeCreate - ref resource type is ", resourceTypeEnum); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_NODE_TEMPLATE, yamlName, uploadComponentInstanceInfo.getName(), uploadComponentInstanceInfo.getType()); + return Either.right(responseFormat); + } + return Either.left(refResource); + } + + private Either<Map<String, UploadComponentInstanceInfo>, ResponseFormat> createResourcesInstanceInfoFromYaml(String yamlFileName, Map<String, Object> toscaJson, Resource resource) { + Map<String, UploadComponentInstanceInfo> moduleComponentInstances = new HashMap<String, UploadComponentInstanceInfo>(); + Either<Map<String, UploadComponentInstanceInfo>, ResponseFormat> result = Either.left(moduleComponentInstances); + Either<Map<String, Object>, ResultStatusEnum> eitherNodesTemlates = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.NODE_TEMPLATES); + if (eitherNodesTemlates.isLeft()) { + Map<String, Object> jsonNodeTemplates = eitherNodesTemlates.left().value(); + + Iterator<Entry<String, Object>> nodesNameValue = jsonNodeTemplates.entrySet().iterator(); + while (nodesNameValue.hasNext()) { + Entry<String, Object> nodeNameValue = nodesNameValue.next(); + Either<UploadComponentInstanceInfo, ResponseFormat> eitherNode = createModuleComponentInstanceInfo(nodeNameValue.getValue()); + if (eitherNode.isRight()) { + log.info("error when creating node template:{}, for resource:{}", nodeNameValue.getKey(), resource.getName()); + return Either.right(eitherNode.right().value()); + } else { + UploadComponentInstanceInfo uploadComponentInstanceInfo = eitherNode.left().value(); + uploadComponentInstanceInfo.setName(nodeNameValue.getKey()); + moduleComponentInstances.put(nodeNameValue.getKey(), uploadComponentInstanceInfo); + } + + } + + } + if (moduleComponentInstances.isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE, yamlFileName); + return Either.right(responseFormat); + } + + return result; + } + + private Either<UploadComponentInstanceInfo, ResponseFormat> createModuleComponentInstanceInfo(Object nodeTemplateJson) { + + UploadComponentInstanceInfo nodeTemplateInfo = new UploadComponentInstanceInfo(); + Either<UploadComponentInstanceInfo, ResponseFormat> result = Either.left(nodeTemplateInfo); + + try { + if (nodeTemplateJson instanceof String) { + String nodeTemplateJsonString = (String) nodeTemplateJson; + nodeTemplateInfo.setType(nodeTemplateJsonString); + } else if (nodeTemplateJson instanceof Map) { + Map<String, Object> nodeTemplateJsonMap = (Map<String, Object>) nodeTemplateJson; + // Type + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) { + nodeTemplateInfo.setType((String) nodeTemplateJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName())); + } + + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.REQUIREMENTS.getElementName())) { + Either<Map<String, List<UploadReqInfo>>, ResponseFormat> regResponse = createReqModuleFromYaml(nodeTemplateInfo, nodeTemplateJsonMap); + if (regResponse.isRight()) + return Either.right(regResponse.right().value()); + if (regResponse.left().value().size() > 0) { + nodeTemplateInfo.setRequirements(regResponse.left().value()); + } + } + + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.CAPABILITIES.getElementName())) { + Either<Map<String, List<UploadCapInfo>>, ResponseFormat> eitherCapRes = createCapModuleFromYaml(nodeTemplateInfo, nodeTemplateJsonMap); + if (eitherCapRes.isRight()) + return Either.right(eitherCapRes.right().value()); + if (eitherCapRes.left().value().size() > 0) { + nodeTemplateInfo.setCapabilities(eitherCapRes.left().value()); + } + } + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) { + Either<Map<String, List<UploadPropInfo>>, ResponseFormat> regResponse = createPropModuleFromYaml(nodeTemplateJsonMap); + if (regResponse.isRight()) + return Either.right(regResponse.right().value()); + if (regResponse.left().value().size() > 0) { + nodeTemplateInfo.setProperties(regResponse.left().value()); + } + } + } else { + + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE)); + + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create capability"); + BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create capability"); + log.debug("error when creating capability, message:{}", e.getMessage(), e); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML)); + } + + return result; + } + + private Either<Map<String, List<UploadPropInfo>>, ResponseFormat> createPropModuleFromYaml(Map<String, Object> nodeTemplateJsonMap) { + Map<String, List<UploadPropInfo>> moduleProp = new HashMap<String, List<UploadPropInfo>>(); + Either<Map<String, List<UploadPropInfo>>, ResponseFormat> response = Either.left(moduleProp); + Either<Map<String, Object>, ResultStatusEnum> toscaProperties = ImportUtils.findFirstToscaMapElement(nodeTemplateJsonMap, ToscaTagNamesEnum.PROPERTIES); + if (toscaProperties.isLeft()) { + Map<String, Object> jsonProperties = toscaProperties.left().value(); + for (Entry<String, Object> jsonPropObj : jsonProperties.entrySet()) { + // Property + String propName = jsonPropObj.getKey(); + Object propValue = jsonPropObj.getValue(); + + if (valueContainsPattern(STR_REPLACE_PATTERN, propValue)) { + log.debug("Ignore property value {}.", propName); + continue; + } + + if (valueContainsPattern(TOKEN_PATTERN, propValue)) { + log.debug("Ignore property value {}.", propName); + continue; + } + if (valueContainsPattern(GET_PROPERTY_PATTERN, propValue)) { + log.debug("Ignore property value {}.", propName); + continue; + } + + if (valueContainsPattern(CONCAT_PATTERN, propValue)) { + log.debug("Ignore property value {}.", propName); + continue; + } + + UploadPropInfo propertyDef = new UploadPropInfo(); + propertyDef.setValue(propValue); + if (propValue instanceof Map) { + if (((Map<String, Object>) propValue).containsKey(ToscaTagNamesEnum.TYPE.getElementName())) { + propertyDef.setType(((Map<String, Object>) propValue).get(ToscaTagNamesEnum.TYPE.getElementName()).toString()); + } + + if (((Map<String, Object>) propValue).containsKey(ToscaTagNamesEnum.GET_INPUT.getElementName()) + || ImportUtils.getPropertyJsonStringValue(propValue, ToscaPropertyType.MAP.getType()).contains(ToscaTagNamesEnum.GET_INPUT.getElementName())) { + createGetInputModuleFromMap(propName, (Map<String, Object>) propValue, propertyDef); + } + + if (((Map<String, Object>) propValue).containsKey(ToscaTagNamesEnum.DESCRIPTION.getElementName())) { + propertyDef.setDescription(((Map<String, Object>) propValue).get(ToscaTagNamesEnum.DESCRIPTION.getElementName()).toString()); + } + if (((Map<String, Object>) propValue).containsKey(ToscaTagNamesEnum.DEFAULT_VALUE.getElementName())) { + propertyDef.setValue(((Map<String, Object>) propValue).get(ToscaTagNamesEnum.DEFAULT_VALUE.getElementName())); + } + if (((Map<String, Object>) propValue).containsKey(ToscaTagNamesEnum.IS_PASSWORD.getElementName())) { + propertyDef.setPassword(Boolean.getBoolean(((Map<String, Object>) propValue).get(ToscaTagNamesEnum.IS_PASSWORD.getElementName()).toString())); + } else { + propertyDef.setValue(propValue); + } + } else if (propValue instanceof List) { + List<Object> propValueList = (List<Object>) propValue; + + createInputPropList(propertyDef, propValueList); + propertyDef.setValue(propValue); + } + + propertyDef.setName(propName); + if (moduleProp.containsKey(propName)) { + moduleProp.get(propName).add(propertyDef); + } else { + List<UploadPropInfo> list = new ArrayList<UploadPropInfo>(); + list.add(propertyDef); + moduleProp.put(propName, list); + } + } + } + return response; + } + + private void createInputPropList(UploadPropInfo propertyDef, List<Object> propValueList) { + for (Object objValue : propValueList) { + + if (objValue instanceof Map) { + Map<String, Object> objMap = (Map<String, Object>) objValue; + Set<String> keys = objMap.keySet(); + for (String key : keys) { + Object value = objMap.get(key); + if (value instanceof Map) { + createGetInputModuleFromMap(key, (Map<String, Object>) value, propertyDef); + + } else if (value instanceof List) { + List<Object> propSubValueList = (List<Object>) value; + + createInputPropList(propertyDef, propSubValueList); + } + + } + + } else if (objValue instanceof List) { + List<Object> propSubValueList = (List<Object>) objValue; + + createInputPropList(propertyDef, propSubValueList); + + } + + } + } + + private void createGetInputModuleFromMap(String propName, Map<String, Object> propValue, UploadPropInfo propertyDef) { + + if (propValue.containsKey(ToscaTagNamesEnum.GET_INPUT.getElementName())) { + Object getInput = propValue.get(ToscaTagNamesEnum.GET_INPUT.getElementName()); + GetInputValueInfo getInputInfo = new GetInputValueInfo(); + List<GetInputValueInfo> getInputs = propertyDef.getGet_input(); + if (getInputs == null) { + getInputs = new ArrayList<GetInputValueInfo>(); + } + if (getInput instanceof String) { + + getInputInfo.setInputName((String) getInput); + getInputInfo.setPropName(propName); + + } else if (getInput instanceof List) { + List<Object> getInputList = (List<Object>) getInput; + getInputInfo.setPropName(propName); + getInputInfo.setInputName((String) getInputList.get(0)); + if (getInputList.size() >= 1) { + Object indexObj = getInputList.get(1); + if (indexObj instanceof Integer) { + getInputInfo.setIndexValue((Integer) indexObj); + } else if (indexObj instanceof Float) { + int index = ((Float) indexObj).intValue(); + getInputInfo.setIndexValue(index); + } else if (indexObj instanceof Map && ((Map<String, Object>) indexObj).containsKey(ToscaTagNamesEnum.GET_INPUT.getElementName())) { + Object index = ((Map<String, Object>) indexObj).get(ToscaTagNamesEnum.GET_INPUT.getElementName()); + GetInputValueInfo getInputInfoIndex = new GetInputValueInfo(); + getInputInfoIndex.setInputName((String) index); + getInputInfoIndex.setPropName(propName); + getInputInfo.setGetInputIndex(getInputInfoIndex); + } + getInputInfo.setList(true); + } + + } + getInputs.add(getInputInfo); + propertyDef.setGet_input(getInputs); + propertyDef.setValue(propValue); + } else { + Set<String> keys = propValue.keySet(); + for (String key : keys) { + Object value = propValue.get(key); + if (value instanceof Map) { + createGetInputModuleFromMap(key, (Map<String, Object>) value, propertyDef); + + } else if (value instanceof List) { + List<Object> valueList = (List<Object>) value; + for (Object o : valueList) { + if (o instanceof Map) { + createGetInputModuleFromMap(key, (Map<String, Object>) o, propertyDef); + + } + } + + } + + } + + } + } + + /* + * private boolean valueContainsStrReplace(Object propValue) { + * + * log.debug("valueContainsStrReplace value is {}", propValue); boolean result = false; if (propValue != null) { log.debug("valueContainsStrReplace value is {}", propValue.getClass()); Matcher matcher = + * STR_REPLACE_PATTERN.matcher(propValue.toString()); result = matcher.find(); } + * + * return result; } + * + * private boolean valueContainsToken(Object propValue) { + * + * log.debug("valueContainsToken value is {}", propValue); boolean result = false; if (propValue != null) { log.debug("valueContainsToken value is {}", propValue.getClass()); Matcher matcher = TOKEN_PATTERN.matcher(propValue.toString()); result = + * matcher.find(); } + * + * return result; } + */ + + private boolean valueContainsPattern(Pattern pattern, Object propValue) { + + log.debug("valueContainsToken value is {}", propValue); + boolean result = false; + if (propValue != null) { + log.debug("valueContainspattern value is {}", propValue.getClass()); + Matcher matcher = pattern.matcher(propValue.toString()); + result = matcher.find(); + } + + return result; + + } + + private Either<Map<String, List<UploadCapInfo>>, ResponseFormat> createCapModuleFromYaml(UploadComponentInstanceInfo nodeTemplateInfo, Map<String, Object> nodeTemplateJsonMap) { + Map<String, List<UploadCapInfo>> moduleCap = new HashMap<String, List<UploadCapInfo>>(); + Either<Map<String, List<UploadCapInfo>>, ResponseFormat> response = Either.left(moduleCap); + Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(nodeTemplateJsonMap, ToscaTagNamesEnum.CAPABILITIES); + if (toscaRequirements.isLeft()) { + List<Object> jsonCapabilities = toscaRequirements.left().value(); + + for (Object jsonCapObj : jsonCapabilities) { + // Requirement + Map<String, Object> capJsonWrapper = (Map<String, Object>) jsonCapObj; + String capName = capJsonWrapper.keySet().iterator().next(); + Either<UploadCapInfo, ResponseFormat> eitherCap = createModuleNodeTemplateCap(capJsonWrapper.get(capName)); + if (eitherCap.isRight()) { + log.info("error when creating Requirement:{}, for node:{}", capName, nodeTemplateInfo); + return Either.right(eitherCap.right().value()); + } else { + UploadCapInfo requirementDef = eitherCap.left().value(); + requirementDef.setName(capName); + if (moduleCap.containsKey(capName)) { + moduleCap.get(capName).add(requirementDef); + } else { + List<UploadCapInfo> list = new ArrayList<UploadCapInfo>(); + list.add(requirementDef); + moduleCap.put(capName, list); + } + + } + } + + } + + return response; + } + + private Either<Map<String, List<UploadReqInfo>>, ResponseFormat> createReqModuleFromYaml(UploadComponentInstanceInfo nodeTemplateInfo, Map<String, Object> nodeTemplateJsonMap) { + Map<String, List<UploadReqInfo>> moduleRequirements = new HashMap<String, List<UploadReqInfo>>(); + Either<Map<String, List<UploadReqInfo>>, ResponseFormat> response = Either.left(moduleRequirements); + Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(nodeTemplateJsonMap, ToscaTagNamesEnum.REQUIREMENTS); + if (toscaRequirements.isLeft()) { + List<Object> jsonRequirements = toscaRequirements.left().value(); + + for (Object jsonRequirementObj : jsonRequirements) { + // Requirement + Map<String, Object> requirementJsonWrapper = (Map<String, Object>) jsonRequirementObj; + String requirementName = requirementJsonWrapper.keySet().iterator().next(); + Either<UploadReqInfo, ResponseFormat> eitherRequirement = createModuleNodeTemplateReg(requirementJsonWrapper.get(requirementName)); + if (eitherRequirement.isRight()) { + log.info("error when creating Requirement:{}, for node:{}", requirementName, nodeTemplateInfo); + return Either.right(eitherRequirement.right().value()); + } else { + UploadReqInfo requirementDef = eitherRequirement.left().value(); + requirementDef.setName(requirementName); + if (moduleRequirements.containsKey(requirementName)) { + moduleRequirements.get(requirementName).add(requirementDef); + } else { + List<UploadReqInfo> list = new ArrayList<UploadReqInfo>(); + list.add(requirementDef); + moduleRequirements.put(requirementName, list); + } + + } + } + + } + return response; + } + + private Either<UploadCapInfo, ResponseFormat> createModuleNodeTemplateCap(Object capObject) { + UploadCapInfo capTemplateInfo = new UploadCapInfo(); + Either<UploadCapInfo, ResponseFormat> result = Either.left(capTemplateInfo); + + if (capObject instanceof String) { + String nodeTemplateJsonString = (String) capObject; + capTemplateInfo.setNode(nodeTemplateJsonString); + } else if (capObject instanceof Map) { + Map<String, Object> nodeTemplateJsonMap = (Map<String, Object>) capObject; + // Type + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.NODE.getElementName())) { + capTemplateInfo.setNode((String) nodeTemplateJsonMap.get(ToscaTagNamesEnum.NODE.getElementName())); + } + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) { + capTemplateInfo.setType((String) nodeTemplateJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName())); + } + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())) { + Either<List<Object>, ResultStatusEnum> validSourceTypesRes = ImportUtils.findFirstToscaListElement(nodeTemplateJsonMap, ToscaTagNamesEnum.VALID_SOURCE_TYPES); + if (validSourceTypesRes.isLeft()) { + capTemplateInfo.setValidSourceTypes(validSourceTypesRes.left().value().stream().map(o -> o.toString()).collect(Collectors.toList())); + } + } + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) { + Either<Map<String, List<UploadPropInfo>>, ResponseFormat> regResponse = createPropModuleFromYaml(nodeTemplateJsonMap); + if (regResponse.isRight()) + return Either.right(regResponse.right().value()); + if (!regResponse.left().value().isEmpty()) { + List<UploadPropInfo> properties = new ArrayList<UploadPropInfo>(); + regResponse.left().value().values().forEach(list -> properties.addAll(list)); + if (!properties.isEmpty()) + capTemplateInfo.setProperties(properties); + } + } + } + + return result; + } + + private Either<UploadReqInfo, ResponseFormat> createModuleNodeTemplateReg(Object regObject) { + + UploadReqInfo regTemplateInfo = new UploadReqInfo(); + Either<UploadReqInfo, ResponseFormat> result = Either.left(regTemplateInfo); + + if (regObject instanceof String) { + String nodeTemplateJsonString = (String) regObject; + regTemplateInfo.setNode(nodeTemplateJsonString); + } else if (regObject instanceof Map) { + Map<String, Object> nodeTemplateJsonMap = (Map<String, Object>) regObject; + // Type + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.NODE.getElementName())) { + regTemplateInfo.setNode((String) nodeTemplateJsonMap.get(ToscaTagNamesEnum.NODE.getElementName())); + } + // US740820 Relate RIs according to capability name + if (nodeTemplateJsonMap.containsKey(ToscaTagNamesEnum.CAPABILITY.getElementName())) { + regTemplateInfo.setCapabilityName((String) nodeTemplateJsonMap.get(ToscaTagNamesEnum.CAPABILITY.getElementName())); + } + } + + return result; + } + + public Either<Resource, ResponseFormat> propagateStateToCertified(User user, Resource resource, LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean inTransaction, boolean needLock) { + Either<Resource, ResponseFormat> result = null; + + // resource updated with checkout. certify the resource + if (resource.getLifecycleState().equals(LifecycleStateEnum.CERTIFIED)) { + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> eitherPopulated = populateToscaArtifacts(resource, user, false, inTransaction, needLock); + result = eitherPopulated.isLeft() ? Either.left(resource) : Either.right(eitherPopulated.right().value()); + return result; + } + try { + result = lifecycleBusinessLogic.changeState(resource.getUniqueId(), user, LifeCycleTransitionEnum.CERTIFICATION_REQUEST, lifecycleChangeInfo, inTransaction, needLock); + if (result.isLeft()) { + resource = result.left().value(); + result = lifecycleBusinessLogic.changeState(resource.getUniqueId(), user, LifeCycleTransitionEnum.START_CERTIFICATION, lifecycleChangeInfo, inTransaction, needLock); + } + if (result.isLeft()) { + resource = result.left().value(); + result = lifecycleBusinessLogic.changeState(resource.getUniqueId(), user, LifeCycleTransitionEnum.CERTIFY, lifecycleChangeInfo, inTransaction, needLock); + } + return result; + } finally { + if (result == null || result.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Change LifecycleState - Certify"); + BeEcompErrorManager.getInstance().logBeSystemError("Change LifecycleState - Certify"); + if (inTransaction == false) { + log.debug("operation failed. do rollback"); + titanGenericDao.rollback(); + } + } else if (inTransaction == false) { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + } + } + + /** + * @deprecated Use {@link #createOrUpdateResourceByImport(Resource,User,boolean, boolean,boolean)} instead + */ + public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> createOrUpdateResourceByImport(Resource resource, User user, AuditingActionEnum auditingEnum, boolean isNormative, boolean needLock) { + return createOrUpdateResourceByImport(resource, user, isNormative, false, needLock); + } + + public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> createOrUpdateResourceByImport(Resource resource, User user, boolean isNormative, boolean isInTransaction, boolean needLock) { + + // check if resource already exist + Either<Resource, StorageOperationStatus> latestByName = resourceOperation.getLatestByName(resource.getName(), true); + Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> result = null; + + // create + if (latestByName.isRight() && latestByName.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + + Either<Resource, StorageOperationStatus> latestByToscaName = resourceOperation.getLatestByToscaResourceName(resource.getToscaResourceName(), true); + if (latestByToscaName.isRight() && latestByToscaName.right().value().equals(StorageOperationStatus.NOT_FOUND)) + result = createResourceByImport(resource, user, isNormative, isInTransaction); + + else { + StorageOperationStatus status = latestByName.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeResourceMissingError, "Create / Update resource by import", resource.getName()); + BeEcompErrorManager.getInstance().logBeComponentMissingError("Create / Update resource by import", ComponentTypeEnum.RESOURCE.getValue(), resource.getName()); + log.debug("resource already exist {}. status={}", resource.getName(), status); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_ALREADY_EXISTS); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + result = Either.right(responseFormat); + } + + } + + // update + else if (latestByName.isLeft()) { + result = updateExistingResourceByImport(resource, latestByName.left().value(), user, isNormative, needLock); + } + + // error + else { + StorageOperationStatus status = latestByName.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeResourceMissingError, "Create / Update resource by import", resource.getName()); + log.debug("failed to get latest version of resource {}. status={}", resource.getName(), status); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(latestByName.right().value()), resource); + componentsUtils.auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + result = Either.right(responseFormat); + } + return result; + + } + + private Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> createResourceByImport(Resource resource, User user, boolean isNormative, boolean isInTransaction) { + log.debug("resource with name {} does not exist. create new resource", resource.getName()); + Either<Resource, ResponseFormat> response = validateResourceBeforeCreate(resource, user, AuditingActionEnum.IMPORT_RESOURCE, isInTransaction); + if (response.isRight()) { + return Either.right(response.right().value()); + } + Either<Resource, ResponseFormat> createResponse = createResourceByDao(resource, user, AuditingActionEnum.IMPORT_RESOURCE, isNormative, isInTransaction); + if (createResponse.isRight()) { + return Either.right(createResponse.right().value()); + } else { + ImmutablePair<Resource, ActionStatus> resourcePair = new ImmutablePair<>(createResponse.left().value(), ActionStatus.CREATED); + ASDCKpiApi.countImportResourcesKPI(); + return Either.left(resourcePair); + + } + } + + public boolean isResourceExist(String resourceName) { + Either<Resource, StorageOperationStatus> latestByName = resourceOperation.getLatestByName(resourceName, false); + return latestByName.isLeft(); + } + + private Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> updateExistingResourceByImport(Resource newResource, Resource oldResource, User user, boolean inTransaction, boolean needLock) { + String lockedResourceId = oldResource.getUniqueId(); + log.debug("found resource: name={}, id={}, version={}, state={}", oldResource.getName(), lockedResourceId, oldResource.getVersion(), oldResource.getLifecycleState()); + Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> result = null; + try { + if (needLock) { + Either<Boolean, ResponseFormat> lockResult = lockComponent(lockedResourceId, oldResource, "Update Resource by Import"); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + } + + Either<Resource, ResponseFormat> prepareResourceForUpdate = prepareResourceForUpdate(oldResource, user, inTransaction, false); + if (prepareResourceForUpdate.isRight()) { + ResponseFormat responseFormat = prepareResourceForUpdate.right().value(); + log.info("resource {} cannot be updated. reason={}", lockedResourceId, responseFormat.getFormattedMessage()); + componentsUtils.auditResource(responseFormat, user, newResource, oldResource.getLifecycleState().name(), oldResource.getVersion(), AuditingActionEnum.IMPORT_RESOURCE, null); + result = Either.right(prepareResourceForUpdate.right().value()); + return result; + } + oldResource = prepareResourceForUpdate.left().value(); + + mergeOldResourceMetadataWithNew(oldResource, newResource); + + Either<Boolean, ResponseFormat> validateFieldsResponse = validateResourceFieldsBeforeUpdate(oldResource, newResource, inTransaction); + if (validateFieldsResponse.isRight()) { + result = Either.right(validateFieldsResponse.right().value()); + return result; + } + + // contact info normalization + newResource.setContactId(newResource.getContactId().toLowerCase()); + // non-updatable fields + newResource.setCreatorUserId(user.getUserId()); + newResource.setCreatorFullName(user.getFullName()); + newResource.setLastUpdaterUserId(user.getUserId()); + newResource.setLastUpdaterFullName(user.getFullName()); + newResource.setUniqueId(oldResource.getUniqueId()); + newResource.setVersion(oldResource.getVersion()); + newResource.setInvariantUUID(oldResource.getInvariantUUID()); + newResource.setLifecycleState(oldResource.getLifecycleState()); + newResource.setUUID(oldResource.getUUID()); + newResource.setNormalizedName(oldResource.getNormalizedName()); + newResource.setSystemName(oldResource.getSystemName()); + if (oldResource.getCsarUUID() != null) { + newResource.setCsarUUID(oldResource.getCsarUUID()); + } + if (oldResource.getImportedToscaChecksum() != null) { + newResource.setImportedToscaChecksum(oldResource.getImportedToscaChecksum()); + } + newResource.setAbstract(oldResource.isAbstract()); + + if (newResource.getDerivedFrom() == null || newResource.getDerivedFrom().isEmpty()) { + newResource.setDerivedFrom(oldResource.getDerivedFrom()); + } + // TODO rhalili: handle artifacts here (delete from old resource and + // add for new) + // TODO rbetzer: remove after migration - in case of resources + // created without tosca artifacts - add the placeholders + if (newResource.getToscaArtifacts() == null || newResource.getToscaArtifacts().isEmpty()) { + setToscaArtifactsPlaceHolders(newResource, user); + } + Either<Resource, StorageOperationStatus> overrideResource = resourceOperation.overrideResource(newResource, oldResource, true); + + if (overrideResource.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(overrideResource.right().value()), newResource); + componentsUtils.auditResource(responseFormat, user, newResource, newResource.getLifecycleState().name(), newResource.getVersion(), AuditingActionEnum.IMPORT_RESOURCE, null); + result = Either.right(responseFormat); + return result; + } + + log.debug("Resource updated successfully!!!"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + componentsUtils.auditResource(responseFormat, user, newResource, oldResource.getLifecycleState().name(), oldResource.getVersion(), AuditingActionEnum.IMPORT_RESOURCE, null); + + ImmutablePair<Resource, ActionStatus> resourcePair = new ImmutablePair<>(overrideResource.left().value(), ActionStatus.OK); + result = Either.left(resourcePair); + return result; + } finally { + if (result == null || result.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Change LifecycleState - Certify"); + BeEcompErrorManager.getInstance().logBeSystemError("Change LifecycleState - Certify"); + log.debug("operation failed. do rollback"); + titanGenericDao.rollback(); + } else if (inTransaction == false) { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + if (needLock == true) { + log.debug("unlock resource {}", lockedResourceId); + graphLockOperation.unlockComponent(lockedResourceId, NodeTypeEnum.Resource); + } + } + + } + + /** + * Merge old resource with new. Keep old category and vendor name without change + * + * @param oldResource + * @param newResource + */ + private void mergeOldResourceMetadataWithNew(Resource oldResource, Resource newResource) { + + // keep old category and vendor name without change + // merge the rest of the resource metadata + if (newResource.getTags() == null || newResource.getTags().isEmpty()) { + newResource.setTags(oldResource.getTags()); + } + + if (newResource.getDescription() == null) { + newResource.setDescription(oldResource.getDescription()); + } + + if (newResource.getVendorRelease() == null) { + newResource.setVendorRelease(oldResource.getVendorRelease()); + } + + if (newResource.getContactId() == null) { + newResource.setContactId(oldResource.getContactId()); + } + + newResource.setCategories(oldResource.getCategories()); + newResource.setVendorName(oldResource.getVendorName()); + } + + private Either<Resource, ResponseFormat> prepareResourceForUpdate(Resource latestResource, User user, boolean inTransaction, boolean needLock) { + + Either<Resource, ResponseFormat> result = Either.left(latestResource); + // check if user can edit resource + if (!ComponentValidationUtils.canWorkOnResource(latestResource, user.getUserId())) { + // checkout + Either<Resource, ResponseFormat> changeState = lifecycleBusinessLogic.changeState(latestResource.getUniqueId(), user, LifeCycleTransitionEnum.CHECKOUT, new LifecycleChangeInfoWithAction("update by import"), inTransaction, needLock); + result = changeState; + } + + return result; + } + + public Either<Resource, ResponseFormat> validateResourceBeforeCreate(Resource resource, User user, AuditingActionEnum actionEnum, boolean inTransaction) { + + Either<Boolean, ResponseFormat> eitherValidation = validateResourceFieldsBeforeCreate(user, getResourceOperation(), resource, actionEnum, inTransaction); + if (eitherValidation.isRight()) { + return Either.right(eitherValidation.right().value()); + } + + eitherValidation = validateCapabilityTypesCreate(user, getCapabilityTypeOperation(), resource, actionEnum, inTransaction); + if (eitherValidation.isRight()) { + return Either.right(eitherValidation.right().value()); + } + eitherValidation = validateLifecycleTypesCreate(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return Either.right(eitherValidation.right().value()); + } + eitherValidation = validateResourceType(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return Either.right(eitherValidation.right().value()); + } + + resource.setCreatorUserId(user.getUserId()); + resource.setCreatorFullName(user.getFirstName() + " " + user.getLastName()); + resource.setContactId(resource.getContactId().toLowerCase()); + if (resource.getResourceType().equals(ResourceTypeEnum.VF)) { + resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VF.name(), resource.getSystemName())); + } + + // Generate invariant UUID - must be here and not in operation since it + // should stay constant during clone + String invariantUUID = UniqueIdBuilder.buildInvariantUUID(); + resource.setInvariantUUID(invariantUUID); + + return Either.left(resource); + } + + private Either<Boolean, ResponseFormat> validateResourceType(User user, Resource resource, AuditingActionEnum actionEnum) { + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + if (resource.getResourceType() == null) { + log.debug("Invalid resource type for resource"); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + eitherResult = Either.right(errorResponse); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + } + return eitherResult; + } + + private Either<Boolean, ResponseFormat> validateLifecycleTypesCreate(User user, Resource resource, AuditingActionEnum actionEnum) { + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + if (resource.getInterfaces() != null && resource.getInterfaces().size() > 0) { + log.debug("validate interface lifecycle Types Exist"); + Iterator<InterfaceDefinition> intItr = resource.getInterfaces().values().iterator(); + while (intItr.hasNext() && eitherResult.isLeft()) { + InterfaceDefinition interfaceDefinition = intItr.next(); + String intType = interfaceDefinition.getUniqueId(); + Either<InterfaceDefinition, StorageOperationStatus> eitherCapTypeFound = interfaceTypeOperation.getInterface(intType); + if (eitherCapTypeFound.isRight()) { + if (eitherCapTypeFound.right().value() == StorageOperationStatus.NOT_FOUND) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInterfaceMissingError, "Create Resource - validateLifecycleTypesCreate", intType); + BeEcompErrorManager.getInstance().logBeGraphObjectMissingError("Create Resource - validateLifecycleTypesCreate", "Interface", intType); + log.debug("Lifecycle Type: {} is required by resource: {} but does not exist in the DB", intType, resource.getName()); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Create Resource - validateLifecycleTypesCreate"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Create Resource - validateLifecycleTypesCreate"); + log.debug("request to data model failed with error: {}", eitherCapTypeFound.right().value().name()); + } + + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_LIFECYCLE_TYPE, intType); + eitherResult = Either.right(errorResponse); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + } + + } + } + return eitherResult; + } + + private Either<Boolean, ResponseFormat> validateCapabilityTypesCreate(User user, ICapabilityTypeOperation capabilityTypeOperation, Resource resource, AuditingActionEnum actionEnum, boolean inTransaction) { + + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + if (resource.getCapabilities() != null && resource.getCapabilities().size() > 0) { + log.debug("validate capability Types Exist - capabilities section"); + + for (String type : resource.getCapabilities().keySet()) { + + eitherResult = validateCapabilityTypeExists(user, capabilityTypeOperation, resource, actionEnum, eitherResult, type, inTransaction); + if (eitherResult.isRight()) { + return Either.right(eitherResult.right().value()); + } + } + } + + if (resource.getRequirements() != null && resource.getRequirements().size() > 0) { + log.debug("validate capability Types Exist - requirements section"); + + for (String type : resource.getRequirements().keySet()) { + + eitherResult = validateCapabilityTypeExists(user, capabilityTypeOperation, resource, actionEnum, eitherResult, type, inTransaction); + if (eitherResult.isRight()) { + return Either.right(eitherResult.right().value()); + } + } + } + + return eitherResult; + } + + private Either<Boolean, ResponseFormat> validateCapabilityTypeExists(User user, ICapabilityTypeOperation capabilityTypeOperation, Resource resource, AuditingActionEnum actionEnum, Either<Boolean, ResponseFormat> eitherResult, String type, + boolean inTransaction) { + Either<CapabilityTypeDefinition, StorageOperationStatus> eitherCapTypeFound = capabilityTypeOperation.getCapabilityType(type, inTransaction); + if (eitherCapTypeFound.isRight()) { + if (eitherCapTypeFound.right().value() == StorageOperationStatus.NOT_FOUND) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeCapabilityTypeMissingError, "Create Resource - validateCapabilityTypesCreate", type); + BeEcompErrorManager.getInstance().logBeGraphObjectMissingError("Create Resource - validateCapabilityTypesCreate", "Capability Type", type); + log.debug("Capability Type: {} is required by resource: {} but does not exist in the DB", type, resource.getName()); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Create Resource - validateCapabilityTypesCreate"); + } + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Create Resource - validateCapabilityTypesCreate"); + log.debug("Trying to get capability type {} failed with error: {}", type, eitherCapTypeFound.right().value().name()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_CAPABILITY_TYPE, type); + eitherResult = Either.right(errorResponse); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + } + return eitherResult; + } + + public Either<Resource, ResponseFormat> createResourceByDao(Resource resource, User user, AuditingActionEnum actionEnum, boolean isNormative) { + return createResourceByDao(resource, user, actionEnum, isNormative, false); + } + + public Either<Resource, ResponseFormat> createResourceByDao(Resource resource, User user, AuditingActionEnum actionEnum, boolean isNormative, boolean inTransaction) { + // create resource + + // lock new resource name in order to avoid creation resource with same + // name + if (inTransaction == false) { + Either<Boolean, ResponseFormat> lockResult = lockComponentByName(resource.getSystemName(), resource, "Create Resource"); + if (lockResult.isRight()) { + ResponseFormat responseFormat = lockResult.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + return Either.right(responseFormat); + } + + log.debug("name is locked {}. status = {}", resource.getSystemName(), lockResult); + } + try { + Either<Resource, ResponseFormat> respStatus = createResourceTransaction(resource, user, actionEnum, isNormative, inTransaction); + if (respStatus.isLeft()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + ASDCKpiApi.countCreatedResourcesKPI(); + } else + componentsUtils.auditResource(respStatus.right().value(), user, resource, "", "", actionEnum, null); + return respStatus; + + } finally { + if (inTransaction == false) { + // graphLockOperation.unlockComponent(resource.getSystemName(), + // NodeTypeEnum.Resource); + graphLockOperation.unlockComponentByName(resource.getSystemName(), resource.getUniqueId(), NodeTypeEnum.Resource); + } + } + } + + private Either<Resource, ResponseFormat> createResourceTransaction(Resource resource, User user, AuditingActionEnum actionEnum, boolean isNormative, boolean inTransaction) { + // validate resource name uniqueness + log.debug("validate resource name"); + Either<Boolean, ResponseFormat> eitherValidation = validateResourceNameExists(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return Either.right(eitherValidation.right().value()); + } + + log.debug("send resource {} to dao for create", resource.getName()); + + createArtifactsPlaceHolderData(resource, user); + + // + if (!isNormative) { + // enrich object + log.debug("enrich resource with creator, version and state"); + resource.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + resource.setVersion(INITIAL_VERSION); + resource.setHighestVersion(true); + resource.setAbstract(false); + } + + Either<Resource, StorageOperationStatus> dataModelResponse = resourceOperation.createResource(resource, inTransaction); + + // Resource created successfully!!! + if (dataModelResponse.isLeft()) { + log.debug("Resource created successfully!!!"); + + return Either.left(dataModelResponse.left().value()); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()), resource); + + return Either.right(responseFormat); + } + + private void createArtifactsPlaceHolderData(Resource resource, User user) { + // create mandatory artifacts + + // TODO it must be removed after that artifact uniqueId creation will be + // moved to ArtifactOperation + // String resourceUniqueId = + // UniqueIdBuilder.buildResourceUniqueId(resource.getResourceName(), + // resource.getResourceVersion()); + + setInformationalArtifactsPlaceHolder(resource, user); + setDeploymentArtifactsPlaceHolder(resource, user); + setToscaArtifactsPlaceHolders(resource, user); + } + + @SuppressWarnings("unchecked") + @Override + public void setDeploymentArtifactsPlaceHolder(Component component, User user) { + Resource resource = (Resource) component; + Map<String, ArtifactDefinition> artifactMap = resource.getDeploymentArtifacts(); + if (artifactMap == null) { + artifactMap = new HashMap<String, ArtifactDefinition>(); + } + Map<String, Object> deploymentResourceArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getDeploymentResourceArtifacts(); + if (deploymentResourceArtifacts != null) { + Iterator<Entry<String, Object>> iterator = deploymentResourceArtifacts.entrySet().iterator(); + while (iterator.hasNext()) { + Entry<String, Object> currEntry = iterator.next(); + boolean shouldCreateArtifact = true; + Map<String, Object> artifactDetails = (Map<String, Object>) currEntry.getValue(); + Object object = artifactDetails.get(PLACE_HOLDER_RESOURCE_TYPES); + if (object != null) { + List<String> artifactTypes = (List<String>) object; + if (!artifactTypes.contains(resource.getResourceType().name())) { + shouldCreateArtifact = false; + continue; + } + } else { + log.info("resource types for artifact placeholder {} were not defined. default is all resources", currEntry.getKey()); + } + if (shouldCreateArtifact) { + if (artifactsBusinessLogic != null) { + ArtifactDefinition artifactDefinition = artifactsBusinessLogic.createArtifactPlaceHolderInfo(resource.getUniqueId(), currEntry.getKey(), (Map<String, Object>) currEntry.getValue(), user, ArtifactGroupTypeEnum.DEPLOYMENT); + if (artifactDefinition != null && !artifactMap.containsKey(artifactDefinition.getArtifactLabel())) + artifactMap.put(artifactDefinition.getArtifactLabel(), artifactDefinition); + } + } + } + } + resource.setDeploymentArtifacts(artifactMap); + } + + private void setInformationalArtifactsPlaceHolder(Resource resource, User user) { + Map<String, ArtifactDefinition> artifactMap = resource.getArtifacts(); + if (artifactMap == null) { + artifactMap = new HashMap<String, ArtifactDefinition>(); + } + String resourceUniqueId = resource.getUniqueId(); + List<String> exludeResourceCategory = ConfigurationManager.getConfigurationManager().getConfiguration().getExcludeResourceCategory(); + Map<String, Object> informationalResourceArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getInformationalResourceArtifacts(); + List<CategoryDefinition> categories = resource.getCategories(); + boolean isCreateArtifact = true; + if (exludeResourceCategory != null) { + String category = categories.get(0).getName(); + for (String exlude : exludeResourceCategory) { + if (exlude.equalsIgnoreCase(category)) { + isCreateArtifact = false; + break; + } + } + + } + + if (informationalResourceArtifacts != null && isCreateArtifact) { + Set<String> keys = informationalResourceArtifacts.keySet(); + for (String informationalResourceArtifactName : keys) { + Map<String, Object> artifactInfoMap = (Map<String, Object>) informationalResourceArtifacts.get(informationalResourceArtifactName); + ArtifactDefinition artifactDefinition = artifactsBusinessLogic.createArtifactPlaceHolderInfo(resourceUniqueId, informationalResourceArtifactName, artifactInfoMap, user, ArtifactGroupTypeEnum.INFORMATIONAL); + artifactMap.put(artifactDefinition.getArtifactLabel(), artifactDefinition); + + } + } + resource.setArtifacts(artifactMap); + } + + /** + * deleteResource + * + * @param resourceId + * @param user + * @return + */ + public ResponseFormat deleteResource(String resourceId, User user) { + ResponseFormat responseFormat; + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, "Delete Resource", false); + if (eitherCreator.isRight()) { + return eitherCreator.right().value(); + } + + Either<Resource, StorageOperationStatus> resourceStatus = resourceOperation.getResource(resourceId); + if (resourceStatus.isRight()) { + log.debug("failed to get resource {}", resourceId); + return componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resourceStatus.right().value()), ""); + } + + Resource resource = resourceStatus.left().value(); + + StorageOperationStatus result = StorageOperationStatus.OK; + Either<Boolean, ResponseFormat> lockResult = lockComponent(resourceId, resource, "Mark resource to delete"); + if (lockResult.isRight()) { + result = StorageOperationStatus.GENERAL_ERROR; + return componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + } + + try { + + result = markComponentToDelete(resource); + if (result.equals(StorageOperationStatus.OK)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT); + } else { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(result); + responseFormat = componentsUtils.getResponseFormatByResource(actionStatus, resource.getName()); + } + return responseFormat; + + } finally { + if (result == null || !result.equals(StorageOperationStatus.OK)) { + log.warn("operation failed. do rollback"); + titanGenericDao.rollback(); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + } + + } + + public ResponseFormat deleteResourceByNameAndVersion(String resourceName, String version, User user) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT); + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, "Delete Resource", false); + if (eitherCreator.isRight()) { + return eitherCreator.right().value(); + } + + // Resource resource = null; + List<Resource> resourcesList = null; + StorageOperationStatus result = StorageOperationStatus.OK; + try { + + Either<List<Resource>, StorageOperationStatus> resourceStatus = resourceOperation.getResourceByNameAndVersion(resourceName, version, true); + if (resourceStatus.isRight()) { + log.debug("failed to get resource {} version {}", resourceName, version); + return componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(resourceStatus.right().value()), resourceName); + } + + resourcesList = resourceStatus.left().value(); + + } finally { + if (result == null || !result.equals(StorageOperationStatus.OK)) { + log.warn("operation failed. do rollback"); + titanGenericDao.rollback(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(result); + responseFormat = componentsUtils.getResponseFormatByResource(actionStatus, resourceName); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + } + for (Resource resource : resourcesList) { + Either<Boolean, ResponseFormat> lockResult = lockComponent(resource.getUniqueId(), resource, "Delete Resource"); + if (lockResult.isRight()) { + result = StorageOperationStatus.GENERAL_ERROR; + return componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + } + try { + result = markComponentToDelete(resource); + if (!result.equals(StorageOperationStatus.OK)) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(result); + responseFormat = componentsUtils.getResponseFormatByResource(actionStatus, resource.getName()); + return responseFormat; + } + + } finally { + if (result == null || !result.equals(StorageOperationStatus.OK)) { + log.warn("operation failed. do rollback"); + titanGenericDao.rollback(); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + graphLockOperation.unlockComponent(resource.getUniqueId(), NodeTypeEnum.Resource); + } + } + return responseFormat; + } + + public Either<Resource, ResponseFormat> getResource(String resourceId, User user) { + + if (user != null) { + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, "Create Resource", false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + } + + IResourceOperation dataModel = getResourceOperation(); + Either<Resource, StorageOperationStatus> storageStatus = dataModel.getResource(resourceId); + + if (storageStatus.isRight()) { + log.debug("failed to get resource by id {}", resourceId); + return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), "")); + } + return Either.left(storageStatus.left().value()); + + } + + public Either<List<Resource>, ResponseFormat> getResourceByNameAndVersion(String resourceName, String resourceVersion, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Resource By Name And Version", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<List<Resource>, StorageOperationStatus> getResource = resourceOperation.getResourceByNameAndVersion(resourceName, resourceVersion, false); + if (getResource.isRight()) { + log.debug("failed to get resource by name {} and version {}", resourceName, resourceVersion); + return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(getResource.right().value()), resourceName)); + } + return Either.left(getResource.left().value()); + } + + /** + * updateResourceMetadata + * + * @param user + * - modifier data (userId) + * @param inTransaction + * TODO + * @param resourceIdToUpdate + * - the resource identifier + * @param newResource + * + * @return Either<Resource, responseFormat> + */ + public Either<Resource, ResponseFormat> updateResourceMetadata(String resourceIdToUpdate, Resource newResource, Resource currentResource, User user, boolean inTransaction) { + + Either<User, ResponseFormat> resp = validateUserExists(user.getUserId(), "update Resource Metadata", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + IResourceOperation dataModel = getResourceOperation(); + log.debug("Get resource with id {}", resourceIdToUpdate); + boolean needToUnlock = false; + boolean rollbackNeeded = true; + + try { + // Either<Resource, StorageOperationStatus> storageStatus = + // dataModel.getResource_tx(resourceIdToUpdate, false); + if (currentResource == null) { + Either<Resource, StorageOperationStatus> storageStatus = dataModel.getResource(resourceIdToUpdate, false); + if (storageStatus.isRight()) { + return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), "")); + } + + currentResource = storageStatus.left().value(); + } + // verify that resource is checked-out and the user is the last + // updater + if (!ComponentValidationUtils.canWorkOnResource(currentResource, user.getUserId())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + // lock resource + StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceIdToUpdate, NodeTypeEnum.Resource); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeFailedLockObjectError, "Upload Artifact - lock " + resourceIdToUpdate + ": " + NodeTypeEnum.Resource); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError("Upload Artifact - lock ", NodeTypeEnum.Resource.getName(), resourceIdToUpdate); + log.debug("Failed to lock resource {} error - {}", resourceIdToUpdate, lockResult); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockResult)); + return Either.right(responseFormat); + } + + needToUnlock = true; + + // critical section starts here + // convert json to object + + // Update and updated resource must have a non-empty "derivedFrom" + // list + // This code is not called from import resources, because of root + // VF "derivedFrom" should be null (or ignored) + if (!currentResource.getResourceType().equals(ResourceTypeEnum.VF)) { + Either<Boolean, ResponseFormat> derivedFromNotEmptyEither = validateDerivedFromNotEmpty(null, newResource, null); + if (derivedFromNotEmptyEither.isRight()) { + log.debug("for updated resource {}, derived from field is empty", newResource.getName()); + return Either.right(derivedFromNotEmptyEither.right().value()); + } + + derivedFromNotEmptyEither = validateDerivedFromNotEmpty(null, currentResource, null); + if (derivedFromNotEmptyEither.isRight()) { + log.debug("for current resource {}, derived from field is empty", currentResource.getName()); + return Either.right(derivedFromNotEmptyEither.right().value()); + } + } else { + newResource.setDerivedFrom(null); + } + + Either<Resource, ResponseFormat> dataModelResponse = updateResourceMetadata(resourceIdToUpdate, newResource, user, currentResource, false, true); + if (dataModelResponse.isRight()) { + log.debug("failed to update resource metadata!!!"); + rollbackNeeded = true; + return Either.right(dataModelResponse.right().value()); + } + + log.debug("Resource metadata updated successfully!!!"); + rollbackNeeded = false; + return Either.left(dataModelResponse.left().value()); + + } finally { + if (!inTransaction) { + if (rollbackNeeded) { + titanGenericDao.rollback(); + } else { + titanGenericDao.commit(); + } + } + + if (needToUnlock) { + graphLockOperation.unlockComponent(resourceIdToUpdate, NodeTypeEnum.Resource); + } + } + } + + private Either<Resource, ResponseFormat> updateResourceMetadata(String resourceIdToUpdate, Resource newResource, User user, Resource currentResource, boolean shouldLock, boolean inTransaction) { + + IResourceOperation dataModel = getResourceOperation(); + Either<Boolean, ResponseFormat> validateResourceFields = validateResourceFieldsBeforeUpdate(currentResource, newResource, inTransaction); + if (validateResourceFields.isRight()) { + return Either.right(validateResourceFields.right().value()); + } + // Setting last updater and uniqueId + newResource.setContactId(newResource.getContactId().toLowerCase()); + newResource.setLastUpdaterUserId(user.getUserId()); + newResource.setUniqueId(resourceIdToUpdate); + // Cannot set highest version through UI + newResource.setHighestVersion(null); + newResource.setCreationDate(currentResource.getCreationDate()); + + Either<Boolean, ResponseFormat> processUpdateOfDerivedFrom = processUpdateOfDerivedFrom(currentResource, newResource, user.getUserId(), shouldLock, inTransaction); + + if (processUpdateOfDerivedFrom.isRight()) { + log.debug("Couldn't update derived from for resource {}", resourceIdToUpdate); + return Either.right(processUpdateOfDerivedFrom.right().value()); + } + + log.debug("send resource {} to dao for update", newResource.getUniqueId()); + Either<Resource, StorageOperationStatus> dataModelResponse = dataModel.updateResource(newResource, inTransaction); + + if (dataModelResponse.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()), newResource); + return Either.right(responseFormat); + } else if (dataModelResponse.left().value() == null) { + log.debug("No response from updateResource"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + return Either.left(dataModelResponse.left().value()); + } + + /** + * validateResourceFieldsBeforeCreate + * + * @param user + * - modifier data (userId) + * @param dataModel + * - IResourceOperation for resource crud + * @param resource + * - Resource object to validate + * @return Either<Boolean, ErrorResponse> + */ + private Either<Boolean, ResponseFormat> validateResourceFieldsBeforeCreate(User user, IResourceOperation dataModel, Resource resource, AuditingActionEnum actionEnum, boolean inTransaction) { + Either<Boolean, ResponseFormat> componentsFieldsValidation = validateComponentFieldsBeforeCreate(user, resource, actionEnum); + if (componentsFieldsValidation.isRight()) { + return componentsFieldsValidation; + } + + // validate name + + /* + * log.debug("validate resource name"); Either<Boolean, ResponseFormat> eitherValidation = validateComponentName(user, resource, actionEnum); if (eitherValidation.isRight()) { return eitherValidation; } + * + * // validate description log.debug("validate description"); eitherValidation = validateDescriptionAndCleanup(user, resource, actionEnum); if (eitherValidation.isRight()) { return eitherValidation; } + */ + + // validate icon + /* + * log.debug("validate icon"); eitherValidation = validateIcon(user, resource, actionEnum); if (eitherValidation.isRight()) { return eitherValidation; } + */ + + // validate tags + /* + * log.debug("validate tags"); eitherValidation = validateTagsListAndRemoveDuplicates(user, resource, actionEnum); if (eitherValidation.isRight()) { return eitherValidation; } + */ + + // validate category + log.debug("validate category"); + Either<Boolean, ResponseFormat> eitherValidation = validateCategory(user, resource, actionEnum, inTransaction); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + // validate vendor name & release + log.debug("validate vendor name"); + eitherValidation = validateVendorName(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate vendor release"); + eitherValidation = validateVendorReleaseName(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + // validate cost + log.debug("validate cost"); + eitherValidation = validateCost(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + // validate licenseType + log.debug("validate licenseType"); + eitherValidation = validateLicenseType(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + // validate template (derived from) + log.debug("validate derived from"); + if (resource.getResourceType().equals(ResourceTypeEnum.VF)) { + resource.setDerivedFrom(null); + } + eitherValidation = validateDerivedFromExist(user, resource, actionEnum); + if (eitherValidation.isRight()) { + return Either.right(eitherValidation.right().value()); + } + + // warn about non-updatable fields + checkComponentFieldsForOverrideAttempt(resource); + String currentCreatorFullName = resource.getCreatorFullName(); + if (currentCreatorFullName != null) { + log.warn("Resource Creator fullname is automatically set and cannot be updated"); + } + + String currentLastUpdaterFullName = resource.getLastUpdaterFullName(); + if (currentLastUpdaterFullName != null) { + log.warn("Resource LastUpdater fullname is automatically set and cannot be updated"); + } + + Long currentLastUpdateDate = resource.getLastUpdateDate(); + if (currentLastUpdateDate != null) { + log.warn("Resource last update date is automatically set and cannot be updated"); + } + + Boolean currentAbstract = resource.isAbstract(); + if (currentAbstract != null) { + log.warn("Resource abstract is automatically set and cannot be updated"); + } + + return Either.left(true); + } + + /** + * validateResourceFieldsBeforeUpdate + * + * @param currentResource + * - Resource object to validate + * @return Either<Boolean, ErrorResponse> + */ + private Either<Boolean, ResponseFormat> validateResourceFieldsBeforeUpdate(Resource currentResource, Resource updateInfoResource, boolean inTransaction) { + + boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentResource.getVersion()); + + // validate resource name + log.debug("validate resource name before update"); + Either<Boolean, ResponseFormat> eitherValidation = validateResourceName(currentResource, updateInfoResource, hasBeenCertified); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + // validate description + log.debug("validate description before update"); + eitherValidation = validateDescriptionAndCleanup(null, updateInfoResource, null); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate icon before update"); + eitherValidation = validateIcon(currentResource, updateInfoResource, hasBeenCertified); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate tags before update"); + eitherValidation = validateTagsListAndRemoveDuplicates(null, updateInfoResource, null); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate vendor name before update"); + eitherValidation = validateVendorName(currentResource, updateInfoResource, hasBeenCertified); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate vendor release before update"); + eitherValidation = validateVendorReleaseName(null, updateInfoResource, null); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate contact info before update"); + eitherValidation = validateContactId(null, updateInfoResource, null); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate derived before update"); + eitherValidation = validateDerivedFromDuringUpdate(currentResource, updateInfoResource, hasBeenCertified); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + log.debug("validate category before update"); + eitherValidation = validateCategory(currentResource, updateInfoResource, hasBeenCertified, inTransaction); + if (eitherValidation.isRight()) { + return eitherValidation; + } + + // warn about non-updatable fields + String currentResourceVersion = currentResource.getVersion(); + String updatedResourceVersion = updateInfoResource.getVersion(); + + if ((updatedResourceVersion != null) && (!updatedResourceVersion.equals(currentResourceVersion))) { + log.warn("Resource version is automatically set and cannot be updated"); + } + + String currentCreatorUserId = currentResource.getCreatorUserId(); + String updatedCreatorUserId = updateInfoResource.getCreatorUserId(); + + if ((updatedCreatorUserId != null) && (!updatedCreatorUserId.equals(currentCreatorUserId))) { + log.warn("Resource Creator User id is automatically set and cannot be updated"); + } + + String currentCreatorFullName = currentResource.getCreatorFullName(); + String updatedCreatorFullName = updateInfoResource.getCreatorFullName(); + + if ((updatedCreatorFullName != null) && (!updatedCreatorFullName.equals(currentCreatorFullName))) { + log.warn("Resource Creator fullname is automatically set and cannot be updated"); + } + + String currentLastUpdaterUserId = currentResource.getLastUpdaterUserId(); + String updatedLastUpdaterUserId = updateInfoResource.getLastUpdaterUserId(); + + if ((updatedLastUpdaterUserId != null) && (!updatedLastUpdaterUserId.equals(currentLastUpdaterUserId))) { + log.warn("Resource LastUpdater userId is automatically set and cannot be updated"); + } + + String currentLastUpdaterFullName = currentResource.getLastUpdaterFullName(); + String updatedLastUpdaterFullName = updateInfoResource.getLastUpdaterFullName(); + + if ((updatedLastUpdaterFullName != null) && (!updatedLastUpdaterFullName.equals(currentLastUpdaterFullName))) { + log.warn("Resource LastUpdater fullname is automatically set and cannot be updated"); + } + + Long currentCreationDate = currentResource.getCreationDate(); + Long updatedCreationDate = updateInfoResource.getCreationDate(); + + if ((updatedCreationDate != null) && (!updatedCreationDate.equals(currentCreationDate))) { + log.warn("Resource Creation date is automatically set and cannot be updated"); + } + + Long currentLastUpdateDate = currentResource.getLastUpdateDate(); + Long updatedLastUpdateDate = updateInfoResource.getLastUpdateDate(); + + if ((updatedLastUpdateDate != null) && (!updatedLastUpdateDate.equals(currentLastUpdateDate))) { + log.warn("Resource last update date is automatically set and cannot be updated"); + } + + LifecycleStateEnum currentLifecycleState = currentResource.getLifecycleState(); + LifecycleStateEnum updatedLifecycleState = updateInfoResource.getLifecycleState(); + + if ((updatedLifecycleState != null) && (!updatedLifecycleState.equals(currentLifecycleState))) { + log.warn("Resource lifecycle state date is automatically set and cannot be updated"); + } + + Boolean currentAbstract = currentResource.isAbstract(); + Boolean updatedAbstract = updateInfoResource.isAbstract(); + + if ((updatedAbstract != null) && (!updatedAbstract.equals(currentAbstract))) { + log.warn("Resource abstract is automatically set and cannot be updated"); + } + + Boolean currentHighestVersion = currentResource.isHighestVersion(); + Boolean updatedHighestVersion = updateInfoResource.isHighestVersion(); + + if ((updatedHighestVersion != null) && (!updatedHighestVersion.equals(currentHighestVersion))) { + log.warn("Resource highest version is automatically set and cannot be updated"); + } + + String currentUuid = currentResource.getUUID(); + String updatedUuid = updateInfoResource.getUUID(); + + if ((updatedUuid != null) && (!updatedUuid.equals(currentUuid))) { + log.warn("Resource UUID is automatically set and cannot be updated"); + } + + ResourceTypeEnum currentResourceType = currentResource.getResourceType(); + ResourceTypeEnum updatedResourceType = updateInfoResource.getResourceType(); + + if ((updatedResourceType != null) && (!updatedResourceType.equals(currentResourceType))) { + log.warn("Resource Type cannot be updated"); + + } + updateInfoResource.setResourceType(currentResource.getResourceType()); + + String currentInvariantUuid = currentResource.getInvariantUUID(); + String updatedInvariantUuid = updateInfoResource.getInvariantUUID(); + + if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) { + log.warn("Resource invariant UUID is automatically set and cannot be updated"); + updateInfoResource.setInvariantUUID(currentInvariantUuid); + } + return Either.left(true); + } + + /* + * private Either<Boolean, ResponseFormat> validateResourceName(User user, Resource resource, AuditingActionEnum actionEnum) { log.debug("validate resource name is not empty"); String resourceName = resource.getResourceName(); + * + * if (!ValidationUtils.validateStringNotEmpty(resourceName)) { log.debug("Resource name is empty"); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()); + * componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); return Either.right(responseFormat); } + * + * if (!ValidationUtils.validateResourceNameLength(resourceName)) { log.debug("Resource name is exceeds max length {} ", ValidationUtils.RESOURCE_NAME_MAX_LENGTH); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus. + * COMPONENT_NAME_EXCEEDS_LIMIT, ComponentTypeEnum.RESOURCE.getValue(), "" + ValidationUtils.RESOURCE_NAME_MAX_LENGTH); componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); return Either.right(responseFormat); + * } + * + * if (!ValidationUtils.validateResourceName(resourceName)) { log.debug("Resource name {} has invalid format", resourceName); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPONENT_NAME, + * ComponentTypeEnum.RESOURCE.getValue()); componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); return Either.right(responseFormat); } resource.setNormalizedName(ValidationUtils.normaliseComponentName( + * resourceName)); resource.setSystemName(ValidationUtils.convertToSystemName(resourceName)) ; + * + * return Either.left(true); } + */ + + private Either<Boolean, ResponseFormat> validateResourceName(Resource currentResource, Resource updateInfoResource, boolean hasBeenCertified) { + String resourceNameUpdated = updateInfoResource.getName(); + String resourceNameCurrent = currentResource.getName(); + if (!resourceNameCurrent.equals(resourceNameUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validateResourceNameResponse = validateComponentName(null, updateInfoResource, null); + if (validateResourceNameResponse.isRight()) { + ResponseFormat errorResponse = validateResourceNameResponse.right().value(); + return Either.right(errorResponse); + } + validateResourceNameResponse = validateResourceNameExists(null, updateInfoResource, null); + if (validateResourceNameResponse.isRight()) { + ResponseFormat errorResponse = validateResourceNameResponse.right().value(); + return Either.right(errorResponse); + } + currentResource.setName(resourceNameUpdated); + currentResource.setNormalizedName(ValidationUtils.normaliseComponentName(resourceNameUpdated)); + currentResource.setSystemName(ValidationUtils.convertToSystemName(resourceNameUpdated)); + + } else { + log.info("Resource name {} cannot be updated once the resource has been certified once.", resourceNameUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NAME_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateIcon(Resource currentResource, Resource updateInfoResource, boolean hasBeenCertified) { + String iconUpdated = updateInfoResource.getIcon(); + String iconCurrent = currentResource.getIcon(); + if (!iconCurrent.equals(iconUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validateIcon = validateIcon(null, updateInfoResource, null); + if (validateIcon.isRight()) { + ResponseFormat errorResponse = validateIcon.right().value(); + return Either.right(errorResponse); + } + } else { + log.info("Icon {} cannot be updated once the resource has been certified once.", iconUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_ICON_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateVendorName(Resource currentResource, Resource updateInfoResource, boolean hasBeenCertified) { + String vendorNameUpdated = updateInfoResource.getVendorName(); + String vendorNameCurrent = currentResource.getVendorName(); + if (!vendorNameCurrent.equals(vendorNameUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validateVendorName = validateVendorName(null, updateInfoResource, null); + if (validateVendorName.isRight()) { + ResponseFormat errorResponse = validateVendorName.right().value(); + return Either.right(errorResponse); + } + } else { + log.info("Vendor name {} cannot be updated once the resource has been certified once.", vendorNameUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateCategory(Resource currentResource, Resource updateInfoResource, boolean hasBeenCertified, boolean inTransaction) { + Either<Boolean, ResponseFormat> validateCategoryName = validateCategory(null, updateInfoResource, null, inTransaction); + if (validateCategoryName.isRight()) { + ResponseFormat errorResponse = validateCategoryName.right().value(); + return Either.right(errorResponse); + } + if (hasBeenCertified) { + CategoryDefinition currentCategory = currentResource.getCategories().get(0); + SubCategoryDefinition currentSubCategory = currentCategory.getSubcategories().get(0); + CategoryDefinition updateCategory = updateInfoResource.getCategories().get(0); + SubCategoryDefinition updtaeSubCategory = updateCategory.getSubcategories().get(0); + if (!currentCategory.getName().equals(updateCategory.getName()) || !currentSubCategory.getName().equals(updtaeSubCategory.getName())) { + log.info("Category {} cannot be updated once the resource has been certified once.", currentResource.getCategories()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_CATEGORY_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateDerivedFromDuringUpdate(Resource currentResource, Resource updateInfoResource, boolean hasBeenCertified) { + + List<String> currentDerivedFrom = currentResource.getDerivedFrom(); + List<String> updatedDerivedFrom = updateInfoResource.getDerivedFrom(); + if (currentDerivedFrom == null || currentDerivedFrom.isEmpty() || updatedDerivedFrom == null || updatedDerivedFrom.isEmpty()) { + log.trace("Update normative types"); + return Either.left(true); + } + + String derivedFromCurrent = currentDerivedFrom.get(0); + String derivedFromUpdated = updatedDerivedFrom.get(0); + + if (!derivedFromCurrent.equals(derivedFromUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validateDerivedFromExistsEither = validateDerivedFromExist(null, updateInfoResource, null); + if (validateDerivedFromExistsEither.isRight()) { + return validateDerivedFromExistsEither; + } + } else { + log.debug("Derived from cannot be updated once the resource has been certified once."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_DERIVED_FROM_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } else { + // For derived from, we must know whether it was actually changed, + // otherwise we must do no action. + // Due to changes it inflicts on data model (remove artifacts, + // properties...), it's not like a flat field which can be + // overwritten if not changed. + // So we must indicate that derived from is not changed + updateInfoResource.setDerivedFrom(null); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateDerivedFromExist(User user, Resource resource, AuditingActionEnum actionEnum) { + + if (resource.getDerivedFrom() == null || resource.getDerivedFrom().isEmpty()) { + return Either.left(true); + } + + IResourceOperation resourceOperation = getResourceOperation(); + + String templateName = resource.getDerivedFrom().get(0); + + Either<Boolean, StorageOperationStatus> dataModelResponse = resourceOperation.validateToscaResourceNameExists(templateName); + if (dataModelResponse.isRight()) { + StorageOperationStatus storageStatus = dataModelResponse.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Create Resource - validateDerivedFromExist"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Create Resource - validateDerivedFromExist"); + log.debug("request to data model failed with error: {}", storageStatus.name()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus), resource); + log.trace("audit before sending response"); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + return Either.right(responseFormat); + } + + if (dataModelResponse.left().value()) { + log.info("resource template with name {} does not exists", templateName); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.PARENT_RESOURCE_NOT_FOUND); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + + return Either.right(responseFormat); + + } + return Either.left(true); + } + + public Either<Boolean, ResponseFormat> validateDerivedFromNotEmpty(User user, Resource resource, AuditingActionEnum actionEnum) { + log.debug("validate resource derivedFrom field"); + if ((resource.getDerivedFrom() == null) || (resource.getDerivedFrom().isEmpty()) || (resource.getDerivedFrom().get(0)) == null || (resource.getDerivedFrom().get(0).trim().isEmpty())) { + log.info("derived from (template) field is missing for the resource"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_DERIVED_FROM_TEMPLATE); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + + return Either.right(responseFormat); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateResourceNameExists(User user, Resource resource, AuditingActionEnum actionEnum) { + + IResourceOperation resourceOperation = getResourceOperation(); + Either<Boolean, StorageOperationStatus> resourceOperationResponse = resourceOperation.validateResourceNameExists(resource.getName(), resource.getResourceType()); + if (resourceOperationResponse.isLeft()) { + if (resourceOperationResponse.left().value()) { + return Either.left(true); + } else { + log.debug("resource with name {} already exists", resource.getName()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, ComponentTypeEnum.RESOURCE.getValue(), resource.getName()); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + return Either.right(errorResponse); + } + } + log.debug("error while validateResourceNameExists for resource: {}", resource.getName()); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resourceOperationResponse.right().value())); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + return Either.right(errorResponse); + } + + /* + * private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Resource resource, AuditingActionEnum actionEnum) { List<String> tagsList = resource.getTags(); + * + * Either<Boolean, ResponseFormat> validateTags = validateResourceTags(tagsList, resource.getResourceName()); if (validateTags.isRight()) { ResponseFormat responseFormat = validateTags.right().value(); + * componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); return Either.right(responseFormat); } ValidationUtils.removeDuplicateFromList(tagsList); return Either.left(true); + * + * } + * + * private Either<Boolean, ResponseFormat> validateResourceTags(List<String> tags, String resourceName) { log.debug("validate resource tags"); boolean includesResourceName = false; int tagListSize = 0; if (tags != null && !tags.isEmpty()) { for + * (String tag : tags) { if (!ValidationUtils.validateTagLength(tag)) { log.debug("tag length exceeds limit {}", ValidationUtils.TAG_MAX_LENGTH); return Either.right(componentsUtils.getResponseFormat(ActionStatus. + * COMPONENT_SINGLE_TAG_EXCEED_LIMIT, "" + ValidationUtils.TAG_MAX_LENGTH)); } if (ValidationUtils.validateComponentNamePattern(tag)) { if (!includesResourceName) { includesResourceName = resourceName.equals(tag); } } else { + * log.debug("invalid tag {}", tag); return Either.right(componentsUtils.getResponseFormat(ActionStatus. COMPONENT_INVALID_TAG)); } tagListSize += tag.length() + 1; } if (!includesResourceName) { log.debug( "tags must include resource name"); + * return Either.right(componentsUtils.getResponseFormat(ActionStatus. COMPONENT_INVALID_TAGS_NO_COMP_NAME)); } if (!ValidationUtils.validateTagListLength(tagListSize)) { log.debug( "overall tags length {}, exceeds limit {}", tagListSize, + * ValidationUtils.TAG_LIST_MAX_LENGTH); return Either.right(componentsUtils.getResponseFormat(ActionStatus. COMPONENT_TAGS_EXCEED_LIMIT, "" + ValidationUtils.TAG_LIST_MAX_LENGTH)); } return Either.left(true); } + * + * return Either.right(componentsUtils.getResponseFormat(ActionStatus. COMPONENT_MISSING_TAGS)); } + */ + + private Either<Boolean, ResponseFormat> validateCategory(User user, Resource resource, AuditingActionEnum actionEnum, boolean inTransaction) { + + List<CategoryDefinition> categories = resource.getCategories(); + if (categories == null || categories.size() == 0) { + log.debug("Resource category is empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + return Either.right(responseFormat); + } + if (categories.size() > 1) { + log.debug("Must be only one category for resource"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_TOO_MUCH_CATEGORIES, ComponentTypeEnum.RESOURCE.getValue()); + return Either.right(responseFormat); + } + CategoryDefinition category = categories.get(0); + List<SubCategoryDefinition> subcategories = category.getSubcategories(); + if (subcategories == null || subcategories.size() == 0) { + log.debug("Missinig subcategory for resource"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY); + return Either.right(responseFormat); + } + if (subcategories.size() > 1) { + log.debug("Must be only one sub ategory for resource"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_TOO_MUCH_SUBCATEGORIES); + return Either.right(responseFormat); + } + + SubCategoryDefinition subcategory = subcategories.get(0); + + if (!ValidationUtils.validateStringNotEmpty(category.getName())) { + log.debug("Resource category is empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + return Either.right(responseFormat); + } + if (!ValidationUtils.validateStringNotEmpty(subcategory.getName())) { + log.debug("Resource category is empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + return Either.right(responseFormat); + } + + Either<Boolean, ResponseFormat> validateCategory = validateCategoryListed(category, subcategory, inTransaction); + if (validateCategory.isRight()) { + ResponseFormat responseFormat = validateCategory.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + return Either.right(responseFormat); + } + + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateCategoryListed(CategoryDefinition category, SubCategoryDefinition subcategory, boolean inTransaction) { + if (category != null && subcategory != null) { + log.debug("validating resource category {} against valid categories list", category); + Either<List<CategoryDefinition>, ActionStatus> categories = elementDao.getAllCategories(NodeTypeEnum.ResourceNewCategory, inTransaction); + if (categories.isRight()) { + log.debug("failed to retrive resource categories from Titan"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(categories.right().value()); + return Either.right(responseFormat); + } + List<CategoryDefinition> categoryList = categories.left().value(); + for (CategoryDefinition cat : categoryList) { + if (cat.getName().equals(category.getName())) { + for (SubCategoryDefinition subcat : cat.getSubcategories()) { + if (subcat.getName().equals(subcategory.getName())) { + return Either.left(true); + } + } + log.debug("SubCategory {} is not part of resource category group. Resource subcategory valid values are {}", subcategory, cat.getSubcategories()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue())); + } + } + log.debug("Category {} is not part of resource category group. Resource category valid values are {}", category, categoryList); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue())); + } + return Either.left(false); + } + + public Either<Boolean, ResponseFormat> validateVendorReleaseName(User user, Resource resource, AuditingActionEnum actionEnum) { + String vendorRelease = resource.getVendorRelease(); + + log.debug("validate vendor relese name"); + if (!ValidationUtils.validateStringNotEmpty(vendorRelease)) { + log.info("vendor relese name is missing."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_VENDOR_RELEASE); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + return Either.right(errorResponse); + } + + Either<Boolean, ResponseFormat> validateVendorReleaseResponse = validateVendorReleaseName(vendorRelease); + if (validateVendorReleaseResponse.isRight()) { + ResponseFormat responseFormat = validateVendorReleaseResponse.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + } + return validateVendorReleaseResponse; + } + + public Either<Boolean, ResponseFormat> validateVendorReleaseName(String vendorRelease) { + if (vendorRelease != null) { + if (!ValidationUtils.validateVendorReleaseLength(vendorRelease)) { + log.info("vendor release exceds limit."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.VENDOR_RELEASE_EXCEEDS_LIMIT, "" + ValidationUtils.VENDOR_RELEASE_MAX_LENGTH); + return Either.right(errorResponse); + } + + if (!ValidationUtils.validateVendorRelease(vendorRelease)) { + log.info("vendor release is not valid."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_VENDOR_RELEASE); + return Either.right(errorResponse); + } + return Either.left(true); + } + return Either.left(false); + + } + + private Either<Boolean, ResponseFormat> validateVendorName(User user, Resource resource, AuditingActionEnum actionEnum) { + String vendorName = resource.getVendorName(); + if (!ValidationUtils.validateStringNotEmpty(vendorName)) { + log.info("vendor name is missing."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_VENDOR_NAME); + componentsUtils.auditResource(errorResponse, user, resource, "", "", actionEnum, null); + return Either.right(errorResponse); + } + + Either<Boolean, ResponseFormat> validateVendorNameResponse = validateVendorName(vendorName); + if (validateVendorNameResponse.isRight()) { + ResponseFormat responseFormat = validateVendorNameResponse.right().value(); + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + } + return validateVendorNameResponse; + + } + + private Either<Boolean, ResponseFormat> validateVendorName(String vendorName) { + if (vendorName != null) { + if (!ValidationUtils.validateVendorNameLength(vendorName)) { + log.info("vendor name exceds limit."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.VENDOR_NAME_EXCEEDS_LIMIT, "" + ValidationUtils.VENDOR_NAME_MAX_LENGTH); + return Either.right(errorResponse); + } + + if (!ValidationUtils.validateVendorName(vendorName)) { + log.info("vendor name is not valid."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_VENDOR_NAME); + return Either.right(errorResponse); + } + return Either.left(true); + + } + return Either.left(false); + + } + + private Either<Boolean, ResponseFormat> validateCost(User user, Resource resource, AuditingActionEnum actionEnum) { + String cost = resource.getCost(); + if (cost != null) { + + if (!ValidationUtils.validateCost(cost)) { + log.debug("resource cost is invalid."); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateLicenseType(User user, Resource resource, AuditingActionEnum actionEnum) { + log.debug("validate licenseType"); + String licenseType = resource.getLicenseType(); + if (licenseType != null) { + List<String> licenseTypes = ConfigurationManager.getConfigurationManager().getConfiguration().getLicenseTypes(); + if (!licenseTypes.contains(licenseType)) { + log.debug("License type {} isn't configured"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + if (actionEnum != null) { + // In update case, no audit is required + componentsUtils.auditResource(responseFormat, user, resource, "", "", actionEnum, null); + } + return Either.right(responseFormat); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> processUpdateOfDerivedFrom(Resource currentResource, Resource updatedResource, String userId, boolean shouldLock, boolean inTransaction) { + Either<Operation, ResponseFormat> deleteArtifactByInterface = null; + if (updatedResource.getDerivedFrom() != null) { + log.debug("Starting derived from update for resource {}", updatedResource.getUniqueId()); + log.debug("1. Removing interface artifacts from graph"); + // Remove all interface artifacts of resource + String resourceId = updatedResource.getUniqueId(); + Map<String, InterfaceDefinition> interfaces = currentResource.getInterfaces(); + + if (interfaces != null) { + Collection<InterfaceDefinition> values = interfaces.values(); + for (InterfaceDefinition interfaceDefinition : values) { + String interfaceType = interfaceTypeOperation.getShortInterfaceName(interfaceDefinition); + + log.trace("Starting interface artifacts removal for interface type {}", interfaceType); + Map<String, Operation> operations = interfaceDefinition.getOperations(); + if (operations != null) { + for (Entry<String, Operation> operationEntry : operations.entrySet()) { + Operation operation = operationEntry.getValue(); + ArtifactDefinition implementation = operation.getImplementation(); + if (implementation != null) { + String uniqueId = implementation.getUniqueId(); + log.debug("Removing interface artifact definition {}, operation {}, interfaceType {}", uniqueId, operationEntry.getKey(), interfaceType); + // only thing that transacts and locks here + deleteArtifactByInterface = artifactsBusinessLogic.deleteArtifactByInterface(resourceId, interfaceType, operationEntry.getKey(), userId, uniqueId, null, shouldLock, true); + if (deleteArtifactByInterface.isRight()) { + log.debug("Couldn't remove artifact definition with id {}", uniqueId); + if (!inTransaction) { + titanGenericDao.rollback(); + } + return Either.right(deleteArtifactByInterface.right().value()); + } + } else { + log.trace("No implementation found for operation {} - nothing to delete", operationEntry.getKey()); + } + } + } else { + log.trace("No operations found for interface type {}", interfaceType); + } + } + } + log.debug("2. Removing properties"); + Either<Map<String, PropertyDefinition>, StorageOperationStatus> findPropertiesOfNode = propertyOperation.deleteAllPropertiesAssociatedToNode(NodeTypeEnum.Resource, resourceId); + + if (findPropertiesOfNode.isRight() && !findPropertiesOfNode.right().value().equals(StorageOperationStatus.OK)) { + log.debug("Failed to remove all properties of resource"); + if (!inTransaction) + titanGenericDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(findPropertiesOfNode.right().value()))); + } + + } else { + log.debug("Derived from wasn't changed during update"); + } + + if (!inTransaction) + titanGenericDao.commit(); + return Either.left(true); + + } + + /**** Auditing *******************/ + + protected static IElementOperation getElementDao(Class<IElementOperation> class1, ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + + return webApplicationContext.getBean(class1); + } + + public ICapabilityTypeOperation getCapabilityTypeOperation() { + return capabilityTypeOperation; + } + + public void setCapabilityTypeOperation(ICapabilityTypeOperation capabilityTypeOperation) { + this.capabilityTypeOperation = capabilityTypeOperation; + } + + public Either<Boolean, ResponseFormat> validatePropertiesDefaultValues(Resource resource) { + log.debug("validate resource properties default values"); + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + List<PropertyDefinition> properties = resource.getProperties(); + String type = null; + String innerType = null; + if (properties != null) { + for (PropertyDefinition property : properties) { + if (!propertyOperation.isPropertyTypeValid(property)) { + log.info("Invalid type for property"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE, property.getType(), property.getName()); + eitherResult = Either.right(responseFormat); + break; + } + + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); + if (allDataTypes.isRight()) { + return Either.right(allDataTypes.right().value()); + } + + type = property.getType(); + if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) { + ImmutablePair<String, Boolean> propertyInnerTypeValid = propertyOperation.isPropertyInnerTypeValid(property, allDataTypes.left().value()); + innerType = propertyInnerTypeValid.getLeft(); + if (!propertyInnerTypeValid.getRight().booleanValue()) { + log.info("Invalid inner type for property"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE, innerType, property.getName()); + eitherResult = Either.right(responseFormat); + break; + } + } + + if (!propertyOperation.isPropertyDefaultValueValid(property, allDataTypes.left().value())) { + log.info("Invalid default value for property"); + ResponseFormat responseFormat; + if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE, property.getName(), type, innerType, property.getDefaultValue()); + } else { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEFAULT_VALUE, property.getName(), type, property.getDefaultValue()); + } + eitherResult = Either.right(responseFormat); + break; + + } + } + } + return eitherResult; + } + + @Override + public Either<List<String>, ResponseFormat> deleteMarkedComponents() { + return deleteMarkedComponents(ComponentTypeEnum.RESOURCE); + } + + @Override + public ComponentInstanceBusinessLogic getComponentInstanceBL() { + return vfComponentInstanceBusinessLogic; + } + + private String getComponentTypeForResponse(Component component) { + String componentTypeForResponse = "SERVICE"; + if (component instanceof Resource) { + componentTypeForResponse = ((Resource) component).getResourceType().name(); + } + return componentTypeForResponse; + } + + private Either<Map<String, GroupDefinition>, ResponseFormat> createGroupsFromYaml(String yamlFileName, Map<String, Object> toscaJson, Resource resource) { + + Map<String, GroupDefinition> groups = new HashMap<String, GroupDefinition>(); + Either<Map<String, GroupDefinition>, ResponseFormat> result = Either.left(groups); + + Either<Map<String, Object>, ResultStatusEnum> eitherNodesTemlates = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.GROUPS); + if (eitherNodesTemlates.isLeft()) { + Map<String, Object> jsonNodeTemplates = eitherNodesTemlates.left().value(); + + if (jsonNodeTemplates != null && false == jsonNodeTemplates.isEmpty()) { + Iterator<Entry<String, Object>> nodesNameValue = jsonNodeTemplates.entrySet().iterator(); + while (nodesNameValue.hasNext()) { + Entry<String, Object> groupNameValue = nodesNameValue.next(); + + String groupName = groupNameValue.getKey(); + Either<GroupDefinition, ResponseFormat> eitherNode = createGroupInfo(groupName, groupNameValue.getValue()); + if (eitherNode.isRight()) { + String message = "Failed when creating group: " + groupNameValue.getKey() + " for resource:" + resource.getName(); + BeEcompErrorManager.getInstance().logInternalFlowError("ImportResource", message, ErrorSeverity.INFO); + return Either.right(eitherNode.right().value()); + } else { + GroupDefinition groupDefinition = eitherNode.left().value(); + groups.put(groupName, groupDefinition); + } + } + } + } + + return result; + } + + private Either<Map<String, InputDefinition>, ResponseFormat> createInputsFromYaml(String yamlFileName, Map<String, Object> toscaJson, Resource resource) { + + Either<Map<String, InputDefinition>, ResultStatusEnum> inputs = ImportUtils.getInputs(toscaJson); + if (inputs.isRight()) { + String message = "Failed when creating inputs: for resource:" + resource.getName(); + BeEcompErrorManager.getInstance().logInternalFlowError("ImportResource", message, ErrorSeverity.INFO); + Map<String, InputDefinition> resultMap = new HashMap(); + return Either.left(resultMap); + + } + + Either<Map<String, InputDefinition>, ResponseFormat> result = Either.left(inputs.left().value()); + + return result; + } + + private Either<GroupDefinition, ResponseFormat> createGroupInfo(String groupName, Object groupTemplateJson) { + + GroupDefinition groupInfo = new GroupDefinition(); + groupInfo.setName(groupName); + Either<GroupDefinition, ResponseFormat> result = Either.left(groupInfo); + + try { + if (groupTemplateJson != null && groupTemplateJson instanceof Map) { + Map<String, Object> groupTemplateJsonMap = (Map<String, Object>) groupTemplateJson; + // Type + String groupType = null; + if (groupTemplateJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) { + groupType = (String) groupTemplateJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName()); + groupInfo.setType(groupType); + } else { + log.debug("The 'type' member is not found under group {}", groupName); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE)); + } + + if (groupTemplateJsonMap.containsKey(ToscaTagNamesEnum.DESCRIPTION.getElementName())) { + groupInfo.setDescription((String) groupTemplateJsonMap.get(ToscaTagNamesEnum.DESCRIPTION.getElementName())); + } + + if (groupTemplateJsonMap.containsKey(ToscaTagNamesEnum.MEMBERS.getElementName())) { + Object members = groupTemplateJsonMap.get(ToscaTagNamesEnum.MEMBERS.getElementName()); + if (members != null) { + if (members instanceof List) { + Map<String, String> membersLoaded = new HashMap<>(); + List<?> membersAsList = (List<?>) members; + for (Object member : membersAsList) { + membersLoaded.put(member.toString(), ""); + } + groupInfo.setMembers(membersLoaded); + } else { + log.debug("The 'type' member is not found under group {}", groupName); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE)); + } + } + } + + if (groupTemplateJsonMap.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) { + Object properties = groupTemplateJsonMap.get(ToscaTagNamesEnum.PROPERTIES.getElementName()); + + Either<List<GroupProperty>, ResponseFormat> regResponse = createPropertiesValueModuleFromYaml(properties, groupName, groupType); + if (regResponse.isRight()) + return Either.right(regResponse.right().value()); + if (regResponse.left().value().size() > 0) { + groupInfo.setProperties(regResponse.left().value()); + } + } + + } else { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE)); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create group"); + log.debug("error when creating group, message:{}", e.getMessage(), e); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML)); + } + + return result; + } + + private Either<List<GroupProperty>, ResponseFormat> createPropertiesValueModuleFromYaml(Object properties, String groupName, String groupType) { + + List<GroupProperty> result = new ArrayList<>(); + + if (properties == null) { + return Either.left(result); + } + + Either<GroupTypeDefinition, StorageOperationStatus> groupTypeRes = groupTypeOperation.getLatestGroupTypeByType(groupType, true); + + if (groupTypeRes.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupType)); + } + + Map<String, PropertyDefinition> gtProperties = new HashMap<>(); + GroupTypeDefinition groupTypeDefinition = groupTypeRes.left().value(); + + List<PropertyDefinition> propertiesDef = groupTypeDefinition.getProperties(); + + if (propertiesDef != null) { + gtProperties = propertiesDef.stream().collect(Collectors.toMap(p -> p.getName(), p -> p)); + } + + if (properties != null) { + + if (properties instanceof Map) { + + Map<String, Object> props = (Map<String, Object>) properties; + for (Entry<String, Object> entry : props.entrySet()) { + + String propName = entry.getKey(); + Object value = entry.getValue(); + + PropertyDefinition gtDefinition = gtProperties.get(propName); + if (gtDefinition == null) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_PROPERTY_NOT_FOUND, propName, groupName, groupType)); + } + + ToscaPropertyType type = ToscaPropertyType.isValidType(gtDefinition.getType()); + + String convertedValue = null; + if (value != null) { + if (type == null || value instanceof Map || value instanceof List) { + convertedValue = gson.toJson(value); + } else { + convertedValue = value.toString(); + } + } + + GroupProperty groupProperty = new GroupProperty(); + groupProperty.setValue(convertedValue); + groupProperty.setName(propName); + + log.debug("After building group property {}", groupProperty); + + result.add(groupProperty); + } + + } + + } + + return Either.left(result); + } + + public Either<Resource, ResponseFormat> getLatestResourceFromCsarUuid(String csarUuid, User user) { + + // validate user + if (user != null) { + Either<User, ResponseFormat> userValidation = validateUserExists(user, "Get resource from csar UUID", false); + if (userValidation.isRight()) { + return Either.right(userValidation.right().value()); + } + } + + // get resource from csar uuid + Either<Resource, StorageOperationStatus> either = resourceOperation.getLatestResourceByCsarOrName(csarUuid, ""); + if (either.isRight()) { + ResponseFormat resp = componentsUtils.getResponseFormat(ActionStatus.RESOURCE_FROM_CSAR_NOT_FOUND, csarUuid); + return Either.right(resp); + } + + return Either.left(either.left().value()); + } + + @Override + public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, ComponentTypeEnum componentTypeEnum, String userId, String searchText) { + return null; + } + + private Either<Map<String, List<CapabilityDefinition>>, ResponseFormat> getValidComponentInstanceCapabilities(Map<String, List<CapabilityDefinition>> defaultCapabilities, Map<String, List<UploadCapInfo>> uploadedCapabilities) { + ResponseFormat responseFormat; + Map<String, List<CapabilityDefinition>> validCapabilitiesMap = new HashMap<>(); + + for (Entry<String, List<UploadCapInfo>> uploadedCapabilitiesEntry : uploadedCapabilities.entrySet()) { + String capabilityType = uploadedCapabilitiesEntry.getValue().get(0).getType(); + if (!defaultCapabilities.containsKey(capabilityType)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_CAPABILITY_TYPE, capabilityType); + return Either.right(responseFormat); + } else { + CapabilityDefinition delaultCapability = defaultCapabilities.get(capabilityType).get(0); + Either<Boolean, String> validationRes = validateUniquenessUpdateUploadedComponentInstanceCapability(delaultCapability, uploadedCapabilitiesEntry.getValue().get(0)); + if (validationRes.isRight()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NAME_ALREADY_EXISTS, validationRes.right().value()); + return Either.right(responseFormat); + } + List<CapabilityDefinition> validCapabilityList = new ArrayList<>(); + validCapabilityList.add(delaultCapability); + validCapabilitiesMap.put(uploadedCapabilitiesEntry.getKey(), validCapabilityList); + } + } + return Either.left(validCapabilitiesMap); + } + + private Either<Boolean, String> validateUniquenessUpdateUploadedComponentInstanceCapability(CapabilityDefinition defaultCapability, UploadCapInfo uploadedCapability) { + List<ComponentInstanceProperty> validProperties = new ArrayList<>(); + Map<String, PropertyDefinition> defaultProperties = defaultCapability.getProperties().stream().collect(Collectors.toMap(PropertyDefinition::getName, Function.identity())); + List<UploadPropInfo> uploadedProperties = uploadedCapability.getProperties(); + for (UploadPropInfo property : uploadedProperties) { + String propertyName = property.getName().toLowerCase(); + String propertyType = property.getType(); + ComponentInstanceProperty validProperty; + if (defaultProperties.containsKey(propertyName)) { + if (propertyType != null && !defaultProperties.get(propertyName).getType().equals(propertyType)) { + return Either.right(propertyName); + } + } + validProperty = new ComponentInstanceProperty(); + validProperty.setName(propertyName); + if (property.getValue() != null) + validProperty.setValue(property.getValue().toString()); + validProperty.setDescription(property.getDescription()); + validProperty.setPassword(property.isPassword()); + validProperties.add(validProperty); + } + defaultCapability.setProperties(validProperties); + return Either.left(true); + } + + public ICacheMangerOperation getCacheManagerOperation() { + return cacheManagerOperation; + } + + public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) { + this.cacheManagerOperation = cacheManagerOperation; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java new file mode 100644 index 0000000000..329481a546 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java @@ -0,0 +1,921 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.servlet.ServletContext; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.auditing.api.IAuditingManager; +import org.openecomp.sdc.be.components.impl.ImportUtils.Constants; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.AttributeDefinition; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.UploadResourceInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.WebApplicationContext; +import org.yaml.snakeyaml.Yaml; + +import fj.data.Either; + +@Component("resourceImportManager") +public class ResourceImportManager { + + private ServletContext servletContext; + + @Autowired + private IAuditingManager auditingManager; + + @Autowired + private ResourceBusinessLogic resourceBusinessLogic; + + @Autowired + private IGraphLockOperation graphLockOperation; + + @Autowired + protected ComponentsUtils componentsUtils; + + @Autowired + protected ResourceOperation resourceOperation; + + @Autowired + protected CapabilityTypeOperation capabilityTypeOperation; + + private ResponseFormatManager responseFormatManager; + + private static Logger log = LoggerFactory.getLogger(ResourceImportManager.class.getName()); + + public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importNormativeResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) { + + LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction(); + lifecycleChangeInfo.setUserRemarks("certification on import"); + Function<Resource, Either<Boolean, ResponseFormat>> validator = (resource) -> resourceBusinessLogic.validatePropertiesDefaultValues(resource); + + return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock); + } + + public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importCertifiedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, Function<Resource, Either<Boolean, ResponseFormat>> validationFunction, + LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean isInTransaction, boolean createNewVersion, boolean needLock) { + Resource resource = new Resource(); + ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<Resource, ActionStatus>(resource, ActionStatus.CREATED); + Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair); + + String latestCertifiedResourceId = null; + try { + setConstantMetaData(resource); + setMetaDataFromJson(resourceMetaData, resource); + + Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource, isInTransaction); + if (validateResourceFromYaml.isRight()) { + ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value(); + auditErrorImport(resourceMetaData, creator, validationErrorResponse, true); + return Either.right(validationErrorResponse); + + } + + Either<Boolean, ResponseFormat> isValidResource = validationFunction.apply(resource); + if (isValidResource.isLeft()) { + // The flag createNewVersion if false doesn't create new version + if (!createNewVersion) { + Either<Resource, StorageOperationStatus> latestByName = resourceOperation.getLatestByName(resource.getName(), isInTransaction); + if (latestByName.isLeft()) { + return Either.right(componentsUtils.getResponseFormatByResource(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resource)); + } + } + + response = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, true, isInTransaction, needLock); + if (response.isLeft()) { + resource = response.left().value().left; + latestCertifiedResourceId = getLatestCertifiedResourceId(resource); + Either<Resource, ResponseFormat> certificationResponse = resourceBusinessLogic.propagateStateToCertified(creator, resource, lifecycleChangeInfo, isInTransaction, needLock); + if (certificationResponse.isRight()) { + response = Either.right(certificationResponse.right().value()); + } else { + responsePair = new ImmutablePair<Resource, ActionStatus>(certificationResponse.left().value(), response.left().value().right); + response = Either.left(responsePair); + } + } + } else { + ResponseFormat validationErrorResponse = isValidResource.right().value(); + auditErrorImport(resourceMetaData, creator, validationErrorResponse, true); + response = Either.right(validationErrorResponse); + } + + } catch (RuntimeException e) { + ResponseFormat exceptionResponse = handleImportResourceExecption(resourceMetaData, creator, true, e); + response = Either.right(exceptionResponse); + } finally { + if (latestCertifiedResourceId != null && needLock) { + log.debug("unlock resource {}", latestCertifiedResourceId); + graphLockOperation.unlockComponent(latestCertifiedResourceId, NodeTypeEnum.Resource); + } + } + + return response; + } + + private String getLatestCertifiedResourceId(Resource resource) { + Map<String, String> allVersions = resource.getAllVersions(); + Double latestCertifiedVersion = 0.0; + if (allVersions != null) { + for (String version : allVersions.keySet()) { + Double dVersion = Double.valueOf(version); + if ((dVersion > latestCertifiedVersion) && (version.endsWith(".0"))) { + latestCertifiedVersion = dVersion; + } + } + return allVersions.get(String.valueOf(latestCertifiedVersion)); + } else { + return null; + } + } + + public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importUserDefinedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean isReusable, boolean isInTransaction) { + + Resource resource = new Resource(); + ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<Resource, ActionStatus>(resource, ActionStatus.CREATED); + Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair); + + try { + setMetaDataFromJson(resourceMetaData, resource); + + Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource, isInTransaction); + if (validateResourceFromYaml.isRight()) { + ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value(); + auditErrorImport(resourceMetaData, creator, validationErrorResponse, false); + return Either.right(validationErrorResponse); + + } + + // currently import VF isn't supported. In future will be supported + // import VF only with CSER file!! + if (ResourceTypeEnum.VF.equals(resource.getResourceType())) { + log.debug("Now import VF isn't supported. It will be supported in future with CSER file only"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + Either<Boolean, ResponseFormat> validateDerivedFromNotEmpty = resourceBusinessLogic.validateDerivedFromNotEmpty(creator, resource, AuditingActionEnum.CREATE_RESOURCE); + if (validateDerivedFromNotEmpty.isRight()) { + return Either.right(validateDerivedFromNotEmpty.right().value()); + } + + Either<Boolean, ResponseFormat> validatePropertiesTypes = resourceBusinessLogic.validatePropertiesDefaultValues(resource); + + if (validatePropertiesTypes.isLeft()) { + response = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, false, isInTransaction, true); + } else { + ResponseFormat validationErrorResponse = validatePropertiesTypes.right().value(); + auditErrorImport(resourceMetaData, creator, validationErrorResponse, false); + response = Either.right(validationErrorResponse); + } + + } catch (RuntimeException e) { + ResponseFormat exceptionResponse = handleImportResourceExecption(resourceMetaData, creator, false, e); + response = Either.right(exceptionResponse); + } + + return response; + + } + + private Either<Boolean, ResponseFormat> populateResourceFromYaml(String resourceYml, Resource resource, boolean inTransaction) { + @SuppressWarnings("unchecked") + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + Map<String, Object> toscaJsonAll = (Map<String, Object>) new Yaml().load(resourceYml); + Map<String, Object> toscaJson = toscaJsonAll; + + // Checks if exist and builds the node_types map + if (toscaJsonAll.containsKey(ToscaTagNamesEnum.NODE_TYPES.getElementName())) { + toscaJson = new HashMap<String, Object>(); + toscaJson.put(ToscaTagNamesEnum.NODE_TYPES.getElementName(), toscaJsonAll.get(ToscaTagNamesEnum.NODE_TYPES.getElementName())); + } + // Derived From + Either<Resource, ResponseFormat> setDerivedFrom = setDerivedFrom(toscaJson, resource, inTransaction); + if (setDerivedFrom.isRight()) { + return Either.right(setDerivedFrom.right().value()); + } + Resource parentResource = setDerivedFrom.left().value(); + setToscaResourceName(toscaJson, resource); + setAttributes(toscaJson, resource); + eitherResult = setCapabilities(toscaJson, resource, parentResource); + if (eitherResult.isRight()) + return eitherResult; + setProperties(toscaJson, resource); + eitherResult = setRequirements(toscaJson, resource, parentResource); + if (eitherResult.isRight()) + return eitherResult; + setInterfaceLifecycle(toscaJson, resource); + + return eitherResult; + } + + private void setToscaResourceName(Map<String, Object> toscaJson, Resource resource) { + Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.NODE_TYPES); + if (toscaElement.isLeft() || toscaElement.left().value().size() == 1) { + String toscaResourceName = toscaElement.left().value().keySet().iterator().next(); + resource.setToscaResourceName(toscaResourceName); + } + } + + private void setInterfaceLifecycle(Map<String, Object> toscaJson, Resource resource) { + Either<Map<String, Object>, ResultStatusEnum> toscaInterfaces = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.INTERFACES); + if (toscaInterfaces.isLeft()) { + Map<String, Object> jsonInterfaces = toscaInterfaces.left().value(); + Map<String, InterfaceDefinition> moduleInterfaces = new HashMap<String, InterfaceDefinition>(); + Iterator<Entry<String, Object>> interfacesNameValue = jsonInterfaces.entrySet().iterator(); + while (interfacesNameValue.hasNext()) { + Entry<String, Object> interfaceNameValue = interfacesNameValue.next(); + Either<InterfaceDefinition, ResultStatusEnum> eitherInterface = createModuleInterface(interfaceNameValue.getValue()); + if (eitherInterface.isRight()) { + log.info("error when creating interface:{}, for resource:{}", interfaceNameValue.getKey(), resource.getName()); + } else { + moduleInterfaces.put(interfaceNameValue.getKey(), eitherInterface.left().value()); + } + + } + if (moduleInterfaces.size() > 0) { + resource.setInterfaces(moduleInterfaces); + } + } + } + + private Either<InterfaceDefinition, ResultStatusEnum> createModuleInterface(Object interfaceJson) { + InterfaceDefinition interf = new InterfaceDefinition(); + Either<InterfaceDefinition, ResultStatusEnum> result = Either.left(interf); + + try { + if (interfaceJson instanceof String) { + String requirementJsonString = (String) interfaceJson; + interf.setType(requirementJsonString); + } else if (interfaceJson instanceof Map) { + Map<String, Object> requirementJsonMap = (Map<String, Object>) interfaceJson; + if (requirementJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) { + String type = (String) requirementJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName()); + interf.setType(type); + interf.setUniqueId(type.toLowerCase()); + } + } else { + result = Either.right(ResultStatusEnum.GENERAL_ERROR); + } + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource- create interface"); + BeEcompErrorManager.getInstance().logBeSystemError("Import Resource- create interface"); + log.debug("error when creating interface, message:{}", e.getMessage(), e); + result = Either.right(ResultStatusEnum.GENERAL_ERROR); + } + + return result; + } + + private Either<Boolean, ResponseFormat> setRequirements(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(toscaJson, ToscaTagNamesEnum.REQUIREMENTS); + if (toscaRequirements.isLeft()) { + List<Object> jsonRequirements = toscaRequirements.left().value(); + Map<String, List<RequirementDefinition>> moduleRequirements = new HashMap<String, List<RequirementDefinition>>(); + // Checking for name duplication + Set<String> reqNames = new HashSet<>(); + // Getting flattened list of capabilities of parent node - cap name + // to cap type + Either<Map<String, String>, ResponseFormat> reqName2Type = getReqName2Type(parentResource); + if (reqName2Type.isRight()) { + ResponseFormat responseFormat = reqName2Type.right().value(); + log.debug("Error during setting requirements of imported resource: {}", responseFormat); + return Either.right(responseFormat); + } + Map<String, String> reqName2TypeMap = reqName2Type.left().value(); + for (Object jsonRequirementObj : jsonRequirements) { + // Requirement + Map<String, Object> requirementJsonWrapper = (Map<String, Object>) jsonRequirementObj; + String requirementName = requirementJsonWrapper.keySet().iterator().next(); + String reqNameLowerCase = requirementName.toLowerCase(); + if (reqNames.contains(reqNameLowerCase)) { + log.debug("More than one requirement with same name {} (case-insensitive) in imported TOSCA file is invalid", reqNameLowerCase); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "requirement", reqNameLowerCase)); + } + reqNames.add(reqNameLowerCase); + Either<RequirementDefinition, ResponseFormat> eitherRequirement = createRequirementFromImportFile(requirementJsonWrapper.get(requirementName)); + if (eitherRequirement.isRight()) { + log.info("error when creating Requirement:{}, for resource:{}", requirementName, resource.getName()); + return Either.right(eitherRequirement.right().value()); + } + RequirementDefinition requirementDef = eitherRequirement.left().value(); + requirementDef.setName(requirementName); + if (moduleRequirements.containsKey(requirementDef.getCapability())) { + moduleRequirements.get(requirementDef.getCapability()).add(requirementDef); + } else { + List<RequirementDefinition> list = new ArrayList<RequirementDefinition>(); + list.add(requirementDef); + moduleRequirements.put(requirementDef.getCapability(), list); + } + + // Validating against req/cap of "derived from" node + Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(reqName2TypeMap, requirementDef.getCapability(), requirementDef.getName()); + if (validateVsParentCap.isRight()) { + return Either.right(validateVsParentCap.right().value()); + } + if (!validateVsParentCap.left().value()) { + log.debug("Requirement with name {} already exists in parent {}", requirementDef.getName(), parentResource.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "requirement", requirementDef.getName().toLowerCase(), parentResource.getName()); + return Either.right(responseFormat); + } + } + if (moduleRequirements.size() > 0) { + resource.setRequirements(moduleRequirements); + } + + } + return eitherResult; + + } + + private Either<RequirementDefinition, ResponseFormat> createRequirementFromImportFile(Object requirementJson) { + RequirementDefinition requirement = new RequirementDefinition(); + Either<RequirementDefinition, ResponseFormat> result = Either.left(requirement); + + try { + if (requirementJson instanceof String) { + String requirementJsonString = (String) requirementJson; + requirement.setCapability(requirementJsonString); + } else if (requirementJson instanceof Map) { + Map<String, Object> requirementJsonMap = (Map<String, Object>) requirementJson; + if (requirementJsonMap.containsKey(ToscaTagNamesEnum.CAPABILITY.getElementName())) { + requirement.setCapability((String) requirementJsonMap.get(ToscaTagNamesEnum.CAPABILITY.getElementName())); + } + + if (requirementJsonMap.containsKey(ToscaTagNamesEnum.NODE.getElementName())) { + requirement.setNode((String) requirementJsonMap.get(ToscaTagNamesEnum.NODE.getElementName())); + } + + if (requirementJsonMap.containsKey(ToscaTagNamesEnum.RELATIONSHIP.getElementName())) { + requirement.setRelationship((String) requirementJsonMap.get(ToscaTagNamesEnum.RELATIONSHIP.getElementName())); + } + if (requirementJsonMap.containsKey(ToscaTagNamesEnum.OCCURRENCES.getElementName())) { + List<Object> occurrencesList = (List) requirementJsonMap.get(ToscaTagNamesEnum.OCCURRENCES.getElementName()); + Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList); + if (validateAndSetOccurrencesStatus.isRight()) { + result = Either.right(validateAndSetOccurrencesStatus.right().value()); + return result; + } + if (validateAndSetOccurrencesStatus.left().value() == true) { + requirement.setMinOccurrences(occurrencesList.get(0).toString()); + requirement.setMaxOccurrences(occurrencesList.get(1).toString()); + } + + } + } else { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML)); + } + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create Requirement"); + BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create Requirement"); + log.debug("error when creating requirement, message:{}", e.getMessage(), e); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML)); + } + + return result; + } + + private ResultStatusEnum setProperties(Map<String, Object> toscaJson, Resource resource) { + Map<String, Object> reducedToscaJson = new HashMap<>(toscaJson); + ImportUtils.removeElementFromJsonMap(reducedToscaJson, "capabilities"); + ResultStatusEnum result = ResultStatusEnum.OK; + Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(reducedToscaJson); + if (properties.isLeft()) { + List<PropertyDefinition> propertiesList = new ArrayList<>(); + Map<String, PropertyDefinition> value = properties.left().value(); + if (value != null) { + for (Entry<String, PropertyDefinition> entry : value.entrySet()) { + String name = entry.getKey(); + PropertyDefinition propertyDefinition = entry.getValue(); + propertyDefinition.setName(name); + propertiesList.add(propertyDefinition); + } + } + resource.setProperties(propertiesList); + } else { + result = properties.right().value(); + } + return result; + } + + private ResultStatusEnum setAttributes(Map<String, Object> toscaJson, Resource resource) { + ResultStatusEnum result = ResultStatusEnum.OK; + Either<Map<String, AttributeDefinition>, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson); + if (attributes.isLeft()) { + List<AttributeDefinition> attributeList = new ArrayList<>(); + Map<String, AttributeDefinition> value = attributes.left().value(); + if (value != null) { + for (Entry<String, AttributeDefinition> entry : value.entrySet()) { + String name = entry.getKey(); + AttributeDefinition attributeDef = entry.getValue(); + attributeDef.setName(name); + attributeList.add(attributeDef); + } + } + resource.setAttributes(attributeList); + } else { + result = attributes.right().value(); + } + return result; + } + + private Either<Resource, ResponseFormat> setDerivedFrom(Map<String, Object> toscaJson, Resource resource, boolean inTransaction) { + Either<String, ResultStatusEnum> toscaDerivedFromElement = ImportUtils.findFirstToscaStringElement(toscaJson, ToscaTagNamesEnum.DERIVED_FROM); + Resource derivedFromResource = null; + if (toscaDerivedFromElement.isLeft()) { + String derivedFrom = toscaDerivedFromElement.left().value(); + log.debug("Derived from TOSCA name is {}", derivedFrom); + resource.setDerivedFrom(Arrays.asList(new String[] { derivedFrom })); + Either<Resource, StorageOperationStatus> latestByToscaResourceName = resourceOperation.getLatestByToscaResourceName(derivedFrom, inTransaction); + if (latestByToscaResourceName.isRight()) { + StorageOperationStatus operationStatus = latestByToscaResourceName.right().value(); + if (operationStatus.equals(StorageOperationStatus.NOT_FOUND)) { + operationStatus = StorageOperationStatus.PARENT_RESOURCE_NOT_FOUND; + } + log.debug("Error when fetching parent resource {}, error: {}", derivedFrom, operationStatus); + ActionStatus convertFromStorageResponse = componentsUtils.convertFromStorageResponse(operationStatus); + BeEcompErrorManager.getInstance().logBeComponentMissingError("Import TOSCA YAML", "resource", derivedFrom); + return Either.right(componentsUtils.getResponseFormat(convertFromStorageResponse, derivedFrom)); + } + derivedFromResource = latestByToscaResourceName.left().value(); + } + return Either.left(derivedFromResource); + } + + private Either<Boolean, ResponseFormat> setCapabilities(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + Either<Map<String, Object>, ResultStatusEnum> toscaCapabilities = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.CAPABILITIES); + if (toscaCapabilities.isLeft()) { + Map<String, Object> jsonCapabilities = toscaCapabilities.left().value(); + Map<String, List<CapabilityDefinition>> moduleCapabilities = new HashMap<String, List<CapabilityDefinition>>(); + Iterator<Entry<String, Object>> capabilitiesNameValue = jsonCapabilities.entrySet().iterator(); + Set<String> capNames = new HashSet<>(); + // Getting flattened list of capabilities of parent node - cap name + // to cap type + Either<Map<String, String>, ResponseFormat> capName2Type = getCapName2Type(parentResource); + if (capName2Type.isRight()) { + ResponseFormat responseFormat = capName2Type.right().value(); + log.debug("Error during setting capabilities of imported resource: {}", responseFormat); + return Either.right(responseFormat); + } + Map<String, String> capName2TypeMap = capName2Type.left().value(); + while (capabilitiesNameValue.hasNext()) { + Entry<String, Object> capabilityNameValue = capabilitiesNameValue.next(); + + // Validating that no req/cap duplicates exist in imported YAML + String capNameLowerCase = capabilityNameValue.getKey().toLowerCase(); + if (capNames.contains(capNameLowerCase)) { + log.debug("More than one capability with same name {} (case-insensitive) in imported TOSCA file is invalid", capNameLowerCase); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "capability", capNameLowerCase)); + } + capNames.add(capNameLowerCase); + + Either<CapabilityDefinition, ResponseFormat> eitherCapability = createCapabilityFromImportFile(capabilityNameValue.getValue()); + if (eitherCapability.isRight()) { + log.debug("error when creating capability:{}, for resource:{}", capabilityNameValue.getKey(), resource.getName()); + return Either.right(eitherCapability.right().value()); + } + + CapabilityDefinition capabilityDef = eitherCapability.left().value(); + capabilityDef.setName(capabilityNameValue.getKey()); + if (moduleCapabilities.containsKey(capabilityDef.getType())) { + moduleCapabilities.get(capabilityDef.getType()).add(capabilityDef); + } else { + List<CapabilityDefinition> list = new ArrayList<CapabilityDefinition>(); + list.add(capabilityDef); + moduleCapabilities.put(capabilityDef.getType(), list); + } + + // Validating against req/cap of "derived from" node + Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(capName2TypeMap, capabilityDef.getType(), capabilityDef.getName()); + if (validateVsParentCap.isRight()) { + return Either.right(validateVsParentCap.right().value()); + } + if (!validateVsParentCap.left().value()) { + // Here parentResource is for sure not null, so it's + // null-safe + log.debug("Capability with name {} already exists in parent {}", capabilityDef.getName(), parentResource.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "capability", capabilityDef.getName().toLowerCase(), parentResource.getName()); + return Either.right(responseFormat); + } + } + if (moduleCapabilities.size() > 0) { + resource.setCapabilities(moduleCapabilities); + } + } + + return eitherResult; + + } + + private Either<Map<String, String>, ResponseFormat> getCapName2Type(Resource parentResource) { + Map<String, String> capName2type = new HashMap<>(); + if (parentResource != null) { + Map<String, List<CapabilityDefinition>> capabilities = parentResource.getCapabilities(); + if (capabilities != null) { + for (List<CapabilityDefinition> capDefinitions : capabilities.values()) { + for (CapabilityDefinition capDefinition : capDefinitions) { + String nameLowerCase = capDefinition.getName().toLowerCase(); + if (capName2type.get(nameLowerCase) != null) { + String parentResourceName = parentResource.getName(); + log.debug("Resource with name {} has more than one capability with name {}, ignoring case", parentResourceName, nameLowerCase); + BeEcompErrorManager.getInstance().logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more capabilities with name " + nameLowerCase, ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + capName2type.put(nameLowerCase, capDefinition.getType()); + } + } + } + } + return Either.left(capName2type); + } + + private Either<Map<String, String>, ResponseFormat> getReqName2Type(Resource parentResource) { + Map<String, String> reqName2type = new HashMap<>(); + if (parentResource != null) { + Map<String, List<RequirementDefinition>> requirements = parentResource.getRequirements(); + if (requirements != null) { + for (List<RequirementDefinition> reqDefinitions : requirements.values()) { + for (RequirementDefinition reqDefinition : reqDefinitions) { + String nameLowerCase = reqDefinition.getName().toLowerCase(); + if (reqName2type.get(nameLowerCase) != null) { + String parentResourceName = parentResource.getName(); + log.debug("Resource with name {} has more than one requirement with name {}, ignoring case", parentResourceName, nameLowerCase); + BeEcompErrorManager.getInstance().logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more requirements with name " + nameLowerCase, ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + reqName2type.put(nameLowerCase, reqDefinition.getCapability()); + } + } + } + } + return Either.left(reqName2type); + } + + private Either<Boolean, ResponseFormat> validateCapNameVsDerived(Map<String, String> parentCapName2Type, String childCapabilityType, String reqCapName) { + String capNameLowerCase = reqCapName.toLowerCase(); + log.trace("Validating capability {} vs parent resource", capNameLowerCase); + String parentCapType = parentCapName2Type.get(capNameLowerCase); + if (parentCapType != null) { + if (childCapabilityType.equals(parentCapType)) { + log.debug("Capability with name {} is of same type {} for imported resource and its parent - this is OK", capNameLowerCase, childCapabilityType); + return Either.left(true); + } + Either<Boolean, StorageOperationStatus> capabilityTypeDerivedFrom = capabilityTypeOperation.isCapabilityTypeDerivedFrom(childCapabilityType, parentCapType); + if (capabilityTypeDerivedFrom.isRight()) { + log.debug("Couldn't check whether imported resource capability derives from its parent's capability"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(capabilityTypeDerivedFrom.right().value())); + return Either.right(responseFormat); + } + return Either.left(capabilityTypeDerivedFrom.left().value()); + } + return Either.left(true); + } + + private Either<CapabilityDefinition, ResponseFormat> createCapabilityFromImportFile(Object capabilityJson) { + + CapabilityDefinition capabilityDefinition = new CapabilityDefinition(); + Either<CapabilityDefinition, ResponseFormat> result = Either.left(capabilityDefinition); + + try { + if (capabilityJson instanceof String) { + String capabilityJsonString = (String) capabilityJson; + capabilityDefinition.setType(capabilityJsonString); + } else if (capabilityJson instanceof Map) { + Map<String, Object> capabilityJsonMap = (Map<String, Object>) capabilityJson; + // Type + if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) { + capabilityDefinition.setType((String) capabilityJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName())); + } + // ValidSourceTypes + if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())) { + capabilityDefinition.setValidSourceTypes((List<String>) capabilityJsonMap.get(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())); + } + // ValidSourceTypes + if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.DESCRIPTION.getElementName())) { + capabilityDefinition.setDescription((String) capabilityJsonMap.get(ToscaTagNamesEnum.DESCRIPTION.getElementName())); + } + if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.OCCURRENCES.getElementName())) { + List<Object> occurrencesList = (List) capabilityJsonMap.get(ToscaTagNamesEnum.OCCURRENCES.getElementName()); + Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList); + if (validateAndSetOccurrencesStatus.isRight()) { + result = Either.right(validateAndSetOccurrencesStatus.right().value()); + return result; + } + if (validateAndSetOccurrencesStatus.left().value() == true) { + capabilityDefinition.setMinOccurrences(occurrencesList.get(0).toString()); + capabilityDefinition.setMaxOccurrences(occurrencesList.get(1).toString()); + } + } + if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) { + + Either<Map<String, PropertyDefinition>, ResultStatusEnum> propertiesRes = ImportUtils.getProperties(capabilityJsonMap); + if (propertiesRes.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND)); + return result; + } else { + propertiesRes.left().value().entrySet().stream().forEach(e -> e.getValue().setName(e.getKey().toLowerCase())); + List<ComponentInstanceProperty> capabilityProperties = propertiesRes.left().value().values().stream().map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null)).collect(Collectors.toList()); + capabilityDefinition.setProperties(capabilityProperties); + } + } + } else { + + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML)); + + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create capability"); + BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create capability"); + log.debug("error when creating capability, message:{}", e.getMessage(), e); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML)); + } + + return result; + } + + private ResponseFormat handleImportResourceExecption(UploadResourceInfo resourceMetaData, User user, boolean isNormative, RuntimeException e) { + String payloadName = (resourceMetaData != null) ? resourceMetaData.getPayloadName() : ""; + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource " + payloadName); + BeEcompErrorManager.getInstance().logBeSystemError("Import Resource " + payloadName); + + log.debug("Error when importing resource from payload:{} Exception text: {}", payloadName, e.getMessage(), e); + ResponseFormat errorResponseWrapper = getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR); + auditErrorImport(resourceMetaData, user, errorResponseWrapper, isNormative); + return errorResponseWrapper; + } + + private void auditErrorImport(UploadResourceInfo resourceMetaData, User user, ResponseFormat errorResponseWrapper, boolean isNormative) { + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, AuditingActionEnum.IMPORT_RESOURCE.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceMetaData.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, ComponentTypeEnum.RESOURCE.getValue()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, user.getUserId()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, errorResponseWrapper.getStatus()); + String message = ""; + if (errorResponseWrapper.getMessageId() != null) { + message = errorResponseWrapper.getMessageId() + ": "; + } + message += errorResponseWrapper.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, user.getFirstName() + " " + user.getLastName()); + + String version, lifeCycleState; + if (isNormative) { + version = Constants.FIRST_CERTIFIED_VERSION_VERSION; + lifeCycleState = LifecycleStateEnum.CERTIFIED.name(); + } else { + version = ""; + lifeCycleState = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name(); + + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, version); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, lifeCycleState); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TOSCA_NODE_TYPE, ""); + + getAuditingManager().auditEvent(auditingFields); + } + + private void setMetaDataFromJson(UploadResourceInfo resourceMetaData, Resource resource) { + resource.setTags(resourceMetaData.getTags()); + List<CategoryDefinition> categories = resourceMetaData.getCategories(); + resource.setCategories(categories); + resource.setDescription(resourceMetaData.getDescription()); + resource.setIcon(resourceMetaData.getResourceIconPath()); + resource.setName(resourceMetaData.getName()); + if (categories != null && !categories.isEmpty()) { + CategoryDefinition categoryDef = categories.get(0); + resource.setAbstract(false); + if (categoryDef != null && categoryDef.getName() != null && categoryDef.getName().equals(Constants.ABSTRACT_CATEGORY_NAME)) { + SubCategoryDefinition subCategoryDef = categoryDef.getSubcategories().get(0); + if (subCategoryDef != null && subCategoryDef.getName().equals(Constants.ABSTRACT_SUBCATEGORY)) { + resource.setAbstract(true); + } + } + } + resource.setContactId(resourceMetaData.getContactId()); + resource.setCreatorUserId(resourceMetaData.getContactId()); + + if (resourceMetaData.getVendorName() != null) { + resource.setVendorName(resourceMetaData.getVendorName()); + } + + if (resourceMetaData.getVendorRelease() != null) { + resource.setVendorRelease(resourceMetaData.getVendorRelease()); + } + + resource.setResourceType(ResourceTypeEnum.valueOf(resourceMetaData.getResourceType())); + + } + + private void setConstantMetaData(Resource resource) { + resource.setVersion(ImportUtils.Constants.FIRST_CERTIFIED_VERSION_VERSION); + ; + resource.setLifecycleState(ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE); + resource.setHighestVersion(ImportUtils.Constants.NORMATIVE_TYPE_HIGHEST_VERSION); + resource.setVendorName(ImportUtils.Constants.VENDOR_NAME); + resource.setVendorRelease(ImportUtils.Constants.VENDOR_RELEASE); + + } + + private Either<Boolean, ResponseFormat> validateOccurrences(List<Object> occurrensesList) { + + if (!ValidationUtils.validateListNotEmpty(occurrensesList)) { + log.debug("Occurrenses list empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + + if (occurrensesList.size() < 2) { + log.debug("Occurrenses list size not 2"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + Object minObj = occurrensesList.get(0); + Object maxObj = occurrensesList.get(1); + Integer minOccurrences = null; + Integer maxOccurrences = null; + if (minObj instanceof Integer) + minOccurrences = (Integer) minObj; + else { + log.debug("Invalid occurrenses format. low_bound occurrense must be Integer {}", minObj); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + if (minOccurrences < 0) { + log.debug("Invalid occurrenses format.low_bound occurrense negative {}", minOccurrences); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + + if (maxObj instanceof String) { + if (maxObj.equals("UNBOUNDED")) { + return Either.left(true); + } else { + log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + } else { + if (maxObj instanceof Integer) + maxOccurrences = (Integer) maxObj; + else { + log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + + if (maxOccurrences <= 0 || maxOccurrences < minOccurrences) { + log.debug("Invalid occurrenses format. min occurrence is {}. Max occurrence is {}", minOccurrences, maxOccurrences); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + } + + return Either.left(true); + + } + + public void init(ServletContext servletContext) { + if (this.servletContext == null) { + synchronized (this) { + if (this.servletContext == null) { + this.servletContext = servletContext; + responseFormatManager = ResponseFormatManager.getInstance(); + resourceBusinessLogic = getResourceBL(servletContext); + } + } + } + } + + public boolean isResourceExist(String resourceName) { + return resourceBusinessLogic.isResourceExist(resourceName); + } + + private ResourceBusinessLogic getResourceBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(org.openecomp.sdc.common.api.Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + ResourceBusinessLogic resourceBl = webApplicationContext.getBean(ResourceBusinessLogic.class); + return resourceBl; + } + + public ServletContext getServletContext() { + return servletContext; + } + + public IAuditingManager getAuditingManager() { + return auditingManager; + } + + public ResponseFormatManager getResponseFormatManager() { + return responseFormatManager; + } + + public void setResponseFormatManager(ResponseFormatManager responseFormatManager) { + this.responseFormatManager = responseFormatManager; + } + + public ResourceBusinessLogic getResourceBusinessLogic() { + return resourceBusinessLogic; + } + + public void setResourceBusinessLogic(ResourceBusinessLogic resourceBusinessLogic) { + this.resourceBusinessLogic = resourceBusinessLogic; + } + + public Logger getLog() { + return log; + } + + public static void setLog(Logger log) { + ResourceImportManager.log = log; + } + + public IGraphLockOperation getGraphLockOperation() { + return graphLockOperation; + } + + public void setGraphLockOperation(IGraphLockOperation graphLockOperation) { + this.graphLockOperation = graphLockOperation; + } + + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public void setAuditingManager(IAuditingManager auditingManager) { + this.auditingManager = auditingManager; + } + + public void setResourceOperation(ResourceOperation resourceOperation) { + this.resourceOperation = resourceOperation; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResponseFormatManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResponseFormatManager.java new file mode 100644 index 0000000000..e8c0bf3d8a --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResponseFormatManager.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.ErrorConfiguration; +import org.openecomp.sdc.be.config.ErrorInfo; +import org.openecomp.sdc.be.config.ErrorInfo.ErrorInfoType; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.OkResponseInfo; +import org.openecomp.sdc.exception.PolicyException; +import org.openecomp.sdc.exception.ResponseFormat; +import org.openecomp.sdc.exception.ServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResponseFormatManager { + + private volatile static ResponseFormatManager instance; + private static ConfigurationManager configurationManager; + private static Logger log = LoggerFactory.getLogger(ResponseFormatManager.class.getName()); + + public static ResponseFormatManager getInstance() { + if (instance == null) { + + instance = init(); + } + return instance; + } + + private static synchronized ResponseFormatManager init() { + if (instance == null) { + instance = new ResponseFormatManager(); + configurationManager = ConfigurationManager.getConfigurationManager(); + } + return instance; + } + + public ResponseFormat getResponseFormat(ActionStatus responseEnum, String... variables) { + ErrorConfiguration errorConfiguration = configurationManager.getErrorConfiguration(); + ErrorInfo errorInfo = errorConfiguration.getErrorInfo(responseEnum.name()); + if (errorInfo == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.EcompErrorNotFound, "ResponseFormatManager", responseEnum.name()); + log.debug("failed to locate {} in error configuration", responseEnum.name()); + errorInfo = errorConfiguration.getErrorInfo(ActionStatus.GENERAL_ERROR.name()); + } + ResponseFormat errorResponseWrapper = new ResponseFormat(errorInfo.getCode()); + String errorMessage = errorInfo.getMessage(); + String errorMessageId = errorInfo.getMessageId(); + ErrorInfoType errorInfoType = errorInfo.getErrorInfoType(); + if (errorInfoType.equals(ErrorInfoType.SERVICE_EXCEPTION)) { + errorResponseWrapper.setServiceException(new ServiceException(errorMessageId, errorMessage, variables)); + } else if (errorInfoType.equals(ErrorInfoType.POLICY_EXCEPTION)) { + errorResponseWrapper.setPolicyException(new PolicyException(errorMessageId, errorMessage, variables)); + } else if (errorInfoType.equals(ErrorInfoType.OK)) { + errorResponseWrapper.setOkResponseInfo(new OkResponseInfo(errorMessageId, errorMessage, variables)); + } + return errorResponseWrapper; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java new file mode 100644 index 0000000000..6bbe88f30c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java @@ -0,0 +1,1768 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.components.distribution.engine.IDistributionEngine; +import org.openecomp.sdc.be.components.distribution.engine.INotificationData; +import org.openecomp.sdc.be.components.distribution.engine.VfModuleArtifactPayload; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.cassandra.AuditCassandraDao; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.GroupTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.DistributionTransitionEnum; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IServiceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.be.model.operations.impl.ServiceOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.resources.data.auditing.AuditingGenericEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionDeployEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionNotificationEvent; +import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.kpi.api.ASDCKpiApi; +import org.openecomp.sdc.common.util.ThreadLocalsHolder; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import fj.data.Either; + +@org.springframework.stereotype.Component("serviceBusinessLogic") +public class ServiceBusinessLogic extends ComponentBusinessLogic { + + private static final String STATUS_SUCCESS_200 = "200"; + + private static final String STATUS_DEPLOYED = "DEPLOYED"; + + @Autowired + private IElementOperation elementDao; + + @Autowired + private IDistributionEngine distributionEngine; + + // @Autowired + // private AuditingDao auditingDao; + + @Autowired + private AuditCassandraDao auditCassandraDao; + + @Autowired + private ServiceComponentInstanceBusinessLogic serviceComponentInstanceBusinessLogic; + + @Autowired + private ICacheMangerOperation cacheManagerOperation; + + private static Logger log = LoggerFactory.getLogger(ServiceBusinessLogic.class.getName()); + private static final String INITIAL_VERSION = "0.1"; + + public ServiceBusinessLogic() { + log.debug("ServiceBusinessLogic started"); + } + + public Either<Service, ResponseFormat> changeServiceDistributionState(String serviceId, String state, LifecycleChangeInfoWithAction commentObj, User user) { + + Either<User, ResponseFormat> resp = validateUserExists(user.getUserId(), "change Service Distribution State", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + log.debug("check request state"); + Either<DistributionTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(state, user); + if (validateEnum.isRight()) { + return Either.right(validateEnum.right().value()); + } + DistributionTransitionEnum distributionTransition = validateEnum.left().value(); + AuditingActionEnum auditAction = (distributionTransition == DistributionTransitionEnum.APPROVE ? AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_APPROV : AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_REJECT); + Either<String, ResponseFormat> commentResponse = validateComment(commentObj, user, auditAction); + if (commentResponse.isRight()) { + return Either.right(commentResponse.right().value()); + } + String comment = commentResponse.left().value(); + + Either<Service, ResponseFormat> validateService = validateServiceDistributionChange(user, serviceId, auditAction, comment); + if (validateService.isRight()) { + return Either.right(validateService.right().value()); + } + Service service = validateService.left().value(); + DistributionStatusEnum initState = service.getDistributionStatus(); + + Either<User, ResponseFormat> validateUser = validateUserDistributionChange(user, service, auditAction, comment); + if (validateUser.isRight()) { + return Either.right(validateUser.right().value()); + } + user = validateUser.left().value(); + + // lock resource + /* + * StorageOperationStatus lockResult = graphLockOperation.lockComponent(serviceId, NodeTypeEnum.Service); if (!lockResult.equals(StorageOperationStatus.OK)) { BeEcompErrorManager.getInstance().processEcompError(EcompErrorName. + * BeFailedLockObjectError, "ChangeServiceDistributionState"); log.debug("Failed to lock service {} error - {}", serviceId, lockResult); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR, + * service.getVersion(), service.getServiceName()); + * + * createAudit(user, auditAction, comment, service, responseFormat); return Either.right(componentsUtils.getResponseFormat(ActionStatus. GENERAL_ERROR)); } + */ + Either<Boolean, ResponseFormat> lockResult = lockComponent(serviceId, service, "ChangeServiceDistributionState"); + if (lockResult.isRight()) { + ResponseFormat responseFormat = lockResult.right().value(); + createAudit(user, auditAction, comment, service, responseFormat); + return Either.right(responseFormat); + } + + try { + + DistributionStatusEnum newState; + if (distributionTransition == DistributionTransitionEnum.APPROVE) { + newState = DistributionStatusEnum.DISTRIBUTION_APPROVED; + } else { + newState = DistributionStatusEnum.DISTRIBUTION_REJECTED; + } + Either<Service, StorageOperationStatus> result = serviceOperation.updateDestributionStatus(service, user, newState); + if (result.isRight()) { + titanGenericDao.rollback(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "ChangeServiceDistributionState"); + BeEcompErrorManager.getInstance().logBeSystemError("ChangeServiceDistributionState"); + log.debug("service {} is change destribuation status failed", service.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR, service.getVersion(), service.getName()); + createAudit(user, auditAction, comment, service, responseFormat); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + titanGenericDao.commit(); + Service updatedService = result.left().value(); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DCURR_STATUS, updatedService.getDistributionStatus().name()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DPREV_STATUS, initState.name()); + createAudit(user, auditAction, comment, updatedService, responseFormat, auditingFields); + return Either.left(result.left().value()); + + } finally { + graphLockOperation.unlockComponent(serviceId, NodeTypeEnum.Service); + } + + } + + public Either<List<Map<String, Object>>, ResponseFormat> getComponentAuditRecords(String componentVersion, String componentUUID, String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Component Audit Records", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<List<Map<String, Object>>, ActionStatus> result; + try { + + // Certified Version + if (componentVersion.endsWith(".0")) { + Either<List<ResourceAdminEvent>, ActionStatus> eitherAuditingForCertified = auditCassandraDao.getByServiceInstanceId(componentUUID); + if (eitherAuditingForCertified.isLeft()) { + result = Either.left(getAuditingFieldsList(eitherAuditingForCertified.left().value())); + } else { + result = Either.right(eitherAuditingForCertified.right().value()); + } + } + // Uncertified Version + else { + result = getAuditRecordsForUncertifiedComponent(componentUUID, componentVersion); + } + } catch (Exception e) { + log.debug("get Audit Records failed with exception {}", e); + result = Either.right(ActionStatus.GENERAL_ERROR); + } + + if (result.isRight()) { + return Either.right(componentsUtils.getResponseFormat(result.right().value())); + } else { + return Either.left(result.left().value()); + } + + } + + private Either<List<Map<String, Object>>, ActionStatus> getAuditRecordsForUncertifiedComponent(String componentUUID, String componentVersion) { + // First Query + Either<List<ResourceAdminEvent>, ActionStatus> eitherprevVerAudit = auditCassandraDao.getAuditByServiceIdAndPrevVersion(componentUUID, componentVersion); + + if (eitherprevVerAudit.isRight()) { + return Either.right(eitherprevVerAudit.right().value()); + } + + // Second Query + Either<List<ResourceAdminEvent>, ActionStatus> eitherCurrVerAudit = auditCassandraDao.getAuditByServiceIdAndCurrVersion(componentUUID, componentVersion); + if (eitherCurrVerAudit.isRight()) { + return Either.right(eitherCurrVerAudit.right().value()); + } + + List<Map<String, Object>> prevVerAuditList = getAuditingFieldsList(eitherprevVerAudit.left().value()); + List<Map<String, Object>> currVerAuditList = getAuditingFieldsList(eitherCurrVerAudit.left().value()); + + List<Map<String, Object>> duplicateElements = new ArrayList<Map<String, Object>>(); + duplicateElements.addAll(prevVerAuditList); + duplicateElements.retainAll(currVerAuditList); + + List<Map<String, Object>> joinedNonDuplicatedList = new ArrayList<Map<String, Object>>(); + joinedNonDuplicatedList.addAll(prevVerAuditList); + joinedNonDuplicatedList.removeAll(duplicateElements); + joinedNonDuplicatedList.addAll(currVerAuditList); + + return Either.left(joinedNonDuplicatedList); + } + + private List<Map<String, Object>> getAuditingFieldsList(List<? extends AuditingGenericEvent> prevVerAuditList) { + + List<Map<String, Object>> prevVerAudit = new ArrayList<Map<String, Object>>(); + for (AuditingGenericEvent auditEvent : prevVerAuditList) { + auditEvent.fillFields(); + prevVerAudit.add(auditEvent.getFields()); + } + return prevVerAudit; + } + + /** + * createService + * + * @param service + * - Service + * @param user + * - modifier data (userId) + * @return Either<Service, responseFormat> + */ + public Either<Service, ResponseFormat> createService(Service service, User user) { + + // get user details + Either<User, ResponseFormat> eitherCreator = validateUser(user, "Create Service", service, AuditingActionEnum.CREATE_RESOURCE, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + // validate user role + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, service, new ArrayList<Role>(), AuditingActionEnum.CREATE_RESOURCE, null); + if (validateRes.isRight()) { + return Either.right(validateRes.right().value()); + } + service.setCreatorUserId(user.getUserId()); + + // warn on overridden fields + checkFieldsForOverideAttampt(service); + // enrich object + log.debug("enrich service with version and state"); + service.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + service.setVersion(INITIAL_VERSION); + service.setDistributionStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + Either<Service, ResponseFormat> createServiceResponse = validateServiceBeforeCreate(service, user, AuditingActionEnum.CREATE_RESOURCE); + if (createServiceResponse.isRight()) { + return createServiceResponse; + } + return createServiceByDao(service, AuditingActionEnum.CREATE_RESOURCE, serviceOperation, user); + } + + private void checkFieldsForOverideAttampt(Service service) { + checkComponentFieldsForOverrideAttempt(service); + if ((service.getDistributionStatus() != null)) { + log.info("Distribution Status cannot be defined by user. This field will be overridden by the application"); + } + } + + private Either<Service, ResponseFormat> createServiceByDao(Service service, AuditingActionEnum actionEnum, IServiceOperation dataModel, User user) { + log.debug("send service {} to dao for create", service.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + + Either<Boolean, ResponseFormat> lockResult = lockComponentByName(service.getSystemName(), service, "Create Service"); + if (lockResult.isRight()) { + ResponseFormat responseFormat = lockResult.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, service, "", "", actionEnum, ComponentTypeEnum.SERVICE); + return Either.right(responseFormat); + } + + log.debug("System name locked is {}, status = {}", service.getSystemName(), lockResult); + + try { + + createMandatoryArtifactsData(service, user); + createServiceApiArtifactsData(service, user); + setToscaArtifactsPlaceHolders(service, user); + + Either<Service, StorageOperationStatus> dataModelResponse = dataModel.createService(service); + + // service created successfully!!! + if (dataModelResponse.isLeft()) { + log.debug("Service created successfully!!!"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + componentsUtils.auditComponentAdmin(responseFormat, user, service, "", "", actionEnum, ComponentTypeEnum.SERVICE); + ASDCKpiApi.countCreatedServicesKPI(); + + Service createdService = dataModelResponse.left().value(); + // //add service to cache + // cacheManagerOperation.updateComponentInCache(createdService.getUniqueId(), + // createdService.getLastUpdateDate(), NodeTypeEnum.Service); + + return Either.left(dataModelResponse.left().value()); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()), service, ComponentTypeEnum.SERVICE); + log.debug("audit before sending response"); + componentsUtils.auditComponentAdmin(responseFormat, user, service, "", "", actionEnum, ComponentTypeEnum.SERVICE); + return Either.right(responseFormat); + + } finally { + graphLockOperation.unlockComponentByName(service.getSystemName(), service.getUniqueId(), NodeTypeEnum.Service); + } + } + + private void createServiceApiArtifactsData(Service service, User user) { + // create mandatory artifacts + + // TODO it must be removed after that artifact uniqueId creation will be + // moved to ArtifactOperation + // String serviceUniqueId = + // UniqueIdBuilder.buildServiceUniqueId(service.getComponentMetadataDefinition().getMetadataDataDefinition().getName(), + // service.getComponentMetadataDefinition().getMetadataDataDefinition().getVersion()); + String serviceUniqueId = service.getUniqueId(); + Map<String, ArtifactDefinition> artifactMap = service.getArtifacts(); + if (artifactMap == null) + artifactMap = new HashMap<String, ArtifactDefinition>(); + + Map<String, Object> serviceApiArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getServiceApiArtifacts(); + List<String> exludeServiceCategory = ConfigurationManager.getConfigurationManager().getConfiguration().getExcludeServiceCategory(); + + List<CategoryDefinition> categories = service.getCategories(); + boolean isCreateArtifact = true; + if (categories != null && exludeServiceCategory != null && !exludeServiceCategory.isEmpty()) { + for (String exlude : exludeServiceCategory) { + if (exlude.equalsIgnoreCase(categories.get(0).getName())) { + isCreateArtifact = false; + break; + } + } + + } + + if (serviceApiArtifacts != null && isCreateArtifact) { + Set<String> keys = serviceApiArtifacts.keySet(); + for (String serviceApiArtifactName : keys) { + Map<String, Object> artifactInfoMap = (Map<String, Object>) serviceApiArtifacts.get(serviceApiArtifactName); + ArtifactDefinition artifactDefinition = createArtifactDefinition(serviceUniqueId, serviceApiArtifactName, artifactInfoMap, user, true); + artifactDefinition.setArtifactGroupType(ArtifactGroupTypeEnum.SERVICE_API); + artifactMap.put(artifactDefinition.getArtifactLabel(), artifactDefinition); + } + + service.setArtifacts(artifactMap); + } + } + + private Either<Service, ResponseFormat> validateServiceBeforeCreate(Service service, User user, AuditingActionEnum actionEnum) { + + Either<Boolean, ResponseFormat> validationResponse = validateServiceFieldsBeforeCreate(user, service, actionEnum); + if (validationResponse.isRight()) { + return Either.right(validationResponse.right().value()); + } + service.setCreatorFullName(user.getFirstName() + " " + user.getLastName()); + service.setContactId(service.getContactId().toLowerCase()); + + // Generate invariant UUID - must be here and not in operation since it + // should stay constant during clone + String invariantUUID = UniqueIdBuilder.buildInvariantUUID(); + service.setInvariantUUID(invariantUUID); + + return Either.left(service); + } + + private Either<Boolean, ResponseFormat> validateServiceFieldsBeforeCreate(User user, Service service, AuditingActionEnum actionEnum) { + Either<Boolean, ResponseFormat> componentsFieldsValidation = validateComponentFieldsBeforeCreate(user, service, actionEnum); + if (componentsFieldsValidation.isRight()) { + return componentsFieldsValidation; + } + + // validate service name uniqueness + log.debug("validate service name uniqueness"); + Either<Boolean, ResponseFormat> serviceNameUniquenessValidation = validateComponentNameUnique(user, service, actionEnum); + if (serviceNameUniquenessValidation.isRight()) { + return serviceNameUniquenessValidation; + } + + // validate category + log.debug("validate category"); + Either<Boolean, ResponseFormat> categoryValidation = validateServiceCategory(user, service, actionEnum); + if (categoryValidation.isRight()) { + return categoryValidation; + } + + log.debug("validate projectName"); + Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, service, actionEnum); + if (projectCodeValidation.isRight()) { + return projectCodeValidation; + } + + return Either.left(true); + + } + + private Either<Boolean, ResponseFormat> validateServiceCategory(User user, Service service, AuditingActionEnum actionEnum) { + log.debug("validate Service category"); + + if (service.getCategories() == null || service.getCategories().size() == 0) { + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.SERVICE.getValue()); + componentsUtils.auditComponentAdmin(errorResponse, user, service, "", "", actionEnum, ComponentTypeEnum.SERVICE); + return Either.right(errorResponse); + } + + Either<Boolean, ResponseFormat> validatCategory = validateServiceCategory(service.getCategories()); + if (validatCategory.isRight()) { + ResponseFormat responseFormat = validatCategory.right().value(); + componentsUtils.auditComponentAdmin(responseFormat, user, service, "", "", actionEnum, ComponentTypeEnum.SERVICE); + return Either.right(responseFormat); + } + + return Either.left(true); + } + + public Either<Map<String, Boolean>, ResponseFormat> validateServiceNameExists(String serviceName, String userId) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "validate Service Name Exists", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + Either<Boolean, StorageOperationStatus> dataModelResponse = serviceOperation.validateServiceNameExists(serviceName); + + if (dataModelResponse.isLeft()) { + Map<String, Boolean> result = new HashMap<>(); + result.put("isValid", dataModelResponse.left().value()); + log.debug("validation was successfully performed."); + return Either.left(result); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value())); + + return Either.right(responseFormat); + } + + public void setElementDao(IElementOperation elementDao) { + this.elementDao = elementDao; + } + + public void setServiceOperation(ServiceOperation serviceOperation) { + this.serviceOperation = serviceOperation; + } + + public void setCassandraAuditingDao(AuditCassandraDao auditingDao) { + this.auditCassandraDao = auditingDao; + } + + /* + * public void setUserAdmin(UserAdminBuisinessLogic userAdmin) { this.userAdmin = userAdmin; } + * + * public void setComponentsUtils(ComponentsUtils componentsUtils) { this.componentsUtils = componentsUtils; } + * + * public void setGraphLockOperation(IGraphLockOperation graphLockOperation) { this.graphLockOperation = graphLockOperation; } + */ + + public ArtifactsBusinessLogic getArtifactBl() { + return artifactsBusinessLogic; + } + + public void setArtifactBl(ArtifactsBusinessLogic artifactBl) { + this.artifactsBusinessLogic = artifactBl; + } + + public Either<Service, ResponseFormat> updateServiceMetadata(String serviceId, Service serviceUpdate, User user) { + Either<User, ResponseFormat> eitherCreator = validateUser(user, "updateServiceMetadata", serviceUpdate, null, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + // validate user role + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, serviceUpdate, new ArrayList<Role>(), null, null); + if (validateRes.isRight()) { + return Either.right(validateRes.right().value()); + } + + Either<Service, StorageOperationStatus> storageStatus = serviceOperation.getService(serviceId); + if (storageStatus.isRight()) { + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.SERVICE), "")); + } + + Service currentService = storageStatus.left().value(); + + if (!ComponentValidationUtils.canWorkOnService(currentService.getUniqueId(), serviceOperation, user.getUserId())) { + log.info("Restricted operation for user {} on service {}", user.getUserId(), currentService.getCreatorUserId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + } + + Either<Service, ResponseFormat> validationRsponse = validateAndUpdateServiceMetadata(user, currentService, serviceUpdate); + if (validationRsponse.isRight()) { + log.info("service update metadata: validations field."); + return validationRsponse; + } + Service serviceToUpdate = validationRsponse.left().value(); + // lock resource + + Either<Boolean, ResponseFormat> lockResult = lockComponent(serviceId, currentService, "Update Service Metadata"); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either<Service, StorageOperationStatus> updateResponse = serviceOperation.updateService(serviceToUpdate, true); + if (updateResponse.isRight()) { + titanGenericDao.rollback(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Update Service Metadata"); + BeEcompErrorManager.getInstance().logBeSystemError("Update Service Metadata"); + log.debug("failed to update sevice {}", serviceToUpdate.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + titanGenericDao.commit(); + return Either.left(updateResponse.left().value()); + } finally { + graphLockOperation.unlockComponent(serviceId, NodeTypeEnum.Service); + } + } + + private Either<Service, ResponseFormat> validateAndUpdateServiceMetadata(User user, Service currentService, Service serviceUpdate) { + + boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentService.getVersion()); + Either<Boolean, ResponseFormat> response = validateAndUpdateCategory(user, currentService, serviceUpdate, hasBeenCertified, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + String creatorUserIdUpdated = serviceUpdate.getCreatorUserId(); + String creatorUserIdCurrent = currentService.getCreatorUserId(); + if (creatorUserIdUpdated != null && !creatorUserIdCurrent.equals(creatorUserIdUpdated)) { + log.info("update srvice: recived request to update creatorUserId to {} the field is not updatable ignoring.", creatorUserIdUpdated); + } + + String creatorFullNameUpdated = serviceUpdate.getCreatorFullName(); + String creatorFullNameCurrent = currentService.getCreatorFullName(); + if (creatorFullNameUpdated != null && !creatorFullNameCurrent.equals(creatorFullNameUpdated)) { + log.info("update srvice: recived request to update creatorFullName to {} the field is not updatable ignoring.", creatorFullNameUpdated); + } + + String lastUpdaterUserIdUpdated = serviceUpdate.getLastUpdaterUserId(); + String lastUpdaterUserIdCurrent = currentService.getLastUpdaterUserId(); + if (lastUpdaterUserIdUpdated != null && !lastUpdaterUserIdCurrent.equals(lastUpdaterUserIdUpdated)) { + log.info("update srvice: recived request to update lastUpdaterUserId to {} the field is not updatable ignoring.", lastUpdaterUserIdUpdated); + } + + String lastUpdaterFullNameUpdated = serviceUpdate.getLastUpdaterFullName(); + String lastUpdaterFullNameCurrent = currentService.getLastUpdaterFullName(); + if (lastUpdaterFullNameUpdated != null && !lastUpdaterFullNameCurrent.equals(lastUpdaterFullNameUpdated)) { + log.info("update srvice: recived request to update lastUpdaterFullName to {} the field is not updatable ignoring.", lastUpdaterFullNameUpdated ); + } + + response = validateAndUpdateServiceName(user, currentService, serviceUpdate, hasBeenCertified, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + DistributionStatusEnum distributionStatusUpdated = serviceUpdate.getDistributionStatus(); + DistributionStatusEnum distributionStatusCurrent = currentService.getDistributionStatus(); + if (distributionStatusUpdated != null && !distributionStatusUpdated.name().equals((distributionStatusCurrent != null ? distributionStatusCurrent.name() : null))) { + log.info("update srvice: recived request to update distributionStatus to {} the field is not updatable ignoring.", distributionStatusUpdated); + } + + if (serviceUpdate.getProjectCode() != null) { + response = validateAndUpdateProjectCode(user, currentService, serviceUpdate, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + } + + response = validateAndUpdateIcon(user, currentService, serviceUpdate, hasBeenCertified, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + Long creationDateUpdated = serviceUpdate.getCreationDate(); + Long creationDateCurrent = currentService.getCreationDate(); + if (creationDateUpdated != null && !creationDateCurrent.equals(creationDateUpdated)) { + log.info("update srvice: recived request to update creationDate to {} the field is not updatable ignoring.", creationDateUpdated); + } + + String versionUpdated = serviceUpdate.getVersion(); + String versionCurrent = currentService.getVersion(); + if (versionUpdated != null && !versionCurrent.equals(versionUpdated)) { + log.info("update srvice: recived request to update version to {} the field is not updatable ignoring.", versionUpdated); + } + + response = validateAndUpdateDescription(user, currentService, serviceUpdate, hasBeenCertified, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateTags(user, currentService, serviceUpdate, hasBeenCertified, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + response = validateAndUpdateContactId(user, currentService, serviceUpdate, null); + if (response.isRight()) { + ResponseFormat errorResponse = response.right().value(); + return Either.right(errorResponse); + } + + Long lastUpdateDateUpdated = serviceUpdate.getLastUpdateDate(); + Long lastUpdateDateCurrent = currentService.getLastUpdateDate(); + if (lastUpdateDateUpdated != null && !lastUpdateDateCurrent.equals(lastUpdateDateUpdated)) { + log.info("update srvice: recived request to update lastUpdateDate to {} the field is not updatable ignoring.", lastUpdateDateUpdated); + } + + LifecycleStateEnum lifecycleStateUpdated = serviceUpdate.getLifecycleState(); + LifecycleStateEnum lifecycleStateCurrent = currentService.getLifecycleState(); + if (lifecycleStateUpdated != null && !lifecycleStateCurrent.name().equals(lifecycleStateUpdated.name())) { + log.info("update srvice: recived request to update lifecycleState to {} the field is not updatable ignoring.", lifecycleStateUpdated); + } + + Boolean isHighestVersionUpdated = serviceUpdate.isHighestVersion(); + Boolean isHighestVersionCurrent = currentService.isHighestVersion(); + if (isHighestVersionUpdated != null && !isHighestVersionCurrent.equals(isHighestVersionUpdated)) { + log.info("update srvice: recived request to update isHighestVersion to {} the field is not updatable ignoring.", isHighestVersionUpdated); + } + + String uuidUpdated = serviceUpdate.getUUID(); + String uuidCurrent = currentService.getUUID(); + if (!uuidCurrent.equals(uuidUpdated)) { + log.info("update srvice: recived request to update uuid to {} the field is not updatable ignoring.", uuidUpdated); + } + + String currentInvariantUuid = currentService.getInvariantUUID(); + String updatedInvariantUuid = serviceUpdate.getInvariantUUID(); + + if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) { + log.warn("Product invariant UUID is automatically set and cannot be updated"); + serviceUpdate.setInvariantUUID(currentInvariantUuid); + } + return Either.left(currentService); + + } + + private Either<Boolean, ResponseFormat> validateAndUpdateContactId(User user, Service currentService, Service serviceUpdate, AuditingActionEnum audatingAction) { + String contactIdUpdated = serviceUpdate.getContactId(); + String contactIdCurrent = currentService.getContactId(); + if (!contactIdCurrent.equals(contactIdUpdated)) { + Either<Boolean, ResponseFormat> validatContactId = validateContactId(user, serviceUpdate, audatingAction); + if (validatContactId.isRight()) { + ResponseFormat errorRespons = validatContactId.right().value(); + return Either.right(errorRespons); + } + currentService.setContactId(contactIdUpdated.toLowerCase()); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Service currentService, Service serviceUpdate, boolean hasBeenCertified, AuditingActionEnum audatingAction) { + List<String> tagsUpdated = serviceUpdate.getTags(); + List<String> tagsCurrent = currentService.getTags(); + if (tagsUpdated == null || tagsUpdated.isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_TAGS); + componentsUtils.auditComponentAdmin(responseFormat, user, serviceUpdate, "", "", audatingAction, ComponentTypeEnum.SERVICE); + return Either.right(responseFormat); + } + + if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) { + Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, serviceUpdate, audatingAction); + if (validatResponse.isRight()) { + ResponseFormat errorRespons = validatResponse.right().value(); + return Either.right(errorRespons); + } + currentService.setTags(tagsUpdated); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateDescription(User user, Service currentService, Service serviceUpdate, boolean hasBeenCertified, AuditingActionEnum audatingAction) { + String descriptionUpdated = serviceUpdate.getDescription(); + String descriptionCurrent = currentService.getDescription(); + if (!descriptionCurrent.equals(descriptionUpdated)) { + Either<Boolean, ResponseFormat> validateDescriptionResponse = validateDescriptionAndCleanup(user, serviceUpdate, audatingAction); + if (validateDescriptionResponse.isRight()) { + ResponseFormat errorRespons = validateDescriptionResponse.right().value(); + return Either.right(errorRespons); + } + currentService.setDescription(serviceUpdate.getDescription()); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateProjectCode(User user, Service currentService, Service serviceUpdate, AuditingActionEnum audatingAction) { + String projectCodeUpdated = serviceUpdate.getProjectCode(); + String projectCodeCurrent = currentService.getProjectCode(); + if (!projectCodeCurrent.equals(projectCodeUpdated)) { + Either<Boolean, ResponseFormat> validatProjectCodeResponse = validateProjectCode(user, serviceUpdate, audatingAction); + if (validatProjectCodeResponse.isRight()) { + ResponseFormat errorRespons = validatProjectCodeResponse.right().value(); + return Either.right(errorRespons); + } + currentService.setProjectCode(projectCodeUpdated); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateIcon(User user, Service currentService, Service serviceUpdate, boolean hasBeenCertified, AuditingActionEnum audatingAction) { + String iconUpdated = serviceUpdate.getIcon(); + String iconCurrent = currentService.getIcon(); + if (!iconCurrent.equals(iconUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validatIconResponse = validateIcon(user, serviceUpdate, audatingAction); + if (validatIconResponse.isRight()) { + ResponseFormat errorRespons = validatIconResponse.right().value(); + return Either.right(errorRespons); + } + currentService.setIcon(iconUpdated); + } else { + log.info("icon {} cannot be updated once the service has been certified once.", iconUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.SERVICE_ICON_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateServiceName(User user, Service currentService, Service serviceUpdate, boolean hasBeenCertified, AuditingActionEnum audatingAction) { + String serviceNameUpdated = serviceUpdate.getName(); + String serviceNameCurrent = currentService.getName(); + if (!serviceNameCurrent.equals(serviceNameUpdated)) { + if (!hasBeenCertified) { + Either<Boolean, ResponseFormat> validatServiceNameResponse = validateComponentName(user, serviceUpdate, audatingAction); + if (validatServiceNameResponse.isRight()) { + ResponseFormat errorRespons = validatServiceNameResponse.right().value(); + return Either.right(errorRespons); + } + + Either<Boolean, ResponseFormat> serviceNameUniquenessValidation = validateComponentNameUnique(user, serviceUpdate, audatingAction); + if (serviceNameUniquenessValidation.isRight()) { + return serviceNameUniquenessValidation; + } + currentService.setName(serviceNameUpdated); + currentService.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(serviceNameUpdated)); + currentService.getComponentMetadataDefinition().getMetadataDataDefinition().setSystemName(ValidationUtils.convertToSystemName(serviceNameUpdated)); + + } else { + log.info("service name {} cannot be updated once the service has been certified once.", serviceNameUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.SERVICE_NAME_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Service currentService, Service serviceUpdate, boolean hasBeenCertified, AuditingActionEnum audatingAction) { + List<CategoryDefinition> categoryUpdated = serviceUpdate.getCategories(); + List<CategoryDefinition> categoryCurrent = currentService.getCategories(); + Either<Boolean, ResponseFormat> validatCategoryResponse = validateServiceCategory(user, serviceUpdate, audatingAction); + if (validatCategoryResponse.isRight()) { + ResponseFormat errorRespons = validatCategoryResponse.right().value(); + return Either.right(errorRespons); + } + if (!categoryCurrent.get(0).getName().equals(categoryUpdated.get(0).getName())) { + if (!hasBeenCertified) { + currentService.setCategories(categoryUpdated); + } else { + log.info("category {} cannot be updated once the service has been certified once.", categoryUpdated); + ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.SERVICE_CATEGORY_CANNOT_BE_CHANGED); + return Either.right(errorResponse); + } + } + return Either.left(true); + + } + + public Either<Boolean, ResponseFormat> validateServiceCategory(List<CategoryDefinition> list) { + if (list != null) { + if (list.size() > 1) { + log.debug("Must be only one category for service"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_TOO_MUCH_CATEGORIES, ComponentTypeEnum.SERVICE.getValue()); + return Either.right(responseFormat); + } + CategoryDefinition category = list.get(0); + if (category.getSubcategories() != null) { + log.debug("Subcategories cannot be defined for service"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.SERVICE_CANNOT_CONTAIN_SUBCATEGORY); + return Either.right(responseFormat); + } + if (!ValidationUtils.validateStringNotEmpty(category.getName())) { + log.debug("Resource category is empty"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.SERVICE.getValue()); + return Either.right(responseFormat); + } + + log.debug("validating service category {} against valid categories list", list); + Either<List<CategoryDefinition>, ActionStatus> categorys = elementDao.getAllServiceCategories(); + if (categorys.isRight()) { + log.debug("failed to retrive service categories from Titan"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(categorys.right().value()); + return Either.right(responseFormat); + } + List<CategoryDefinition> categoryList = categorys.left().value(); + for (CategoryDefinition value : categoryList) { + if (value.getName().equals(category.getName())) { + return Either.left(true); + } + } + log.debug("Category {} is not part of service category group. Service category valid values are {}", list, categoryList); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.SERVICE.getValue())); + } + return Either.left(false); + } + + public ResponseFormat deleteService(String serviceId, User user) { + ResponseFormat responseFormat; + String ecompErrorContext = "delete service"; + + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false); + if (eitherCreator.isRight()) { + return eitherCreator.right().value(); + } + user = eitherCreator.left().value(); + + Either<Service, StorageOperationStatus> serviceStatus = serviceOperation.getService(serviceId); + if (serviceStatus.isRight()) { + log.debug("failed to get service {}", serviceId); + return componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(serviceStatus.right().value()), ""); + } + + Service service = serviceStatus.left().value(); + + StorageOperationStatus result = StorageOperationStatus.OK; + Either<Boolean, ResponseFormat> lockResult = lockComponent(service, "Mark service to delete"); + if (lockResult.isRight()) { + result = StorageOperationStatus.GENERAL_ERROR; + return componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + } + + try { + + result = markComponentToDelete(service); + if (result.equals(StorageOperationStatus.OK)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT); + } else { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(result); + responseFormat = componentsUtils.getResponseFormatByResource(actionStatus, service.getName()); + } + return responseFormat; + + } finally { + if (result == null || !result.equals(StorageOperationStatus.OK)) { + log.warn("operation failed. do rollback"); + BeEcompErrorManager.getInstance().logBeSystemError("Delete Service"); + titanGenericDao.rollback(); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + graphLockOperation.unlockComponent(serviceId, NodeTypeEnum.Service); + } + } + + public ResponseFormat deleteServiceByNameAndVersion(String serviceName, String version, User user) { + ResponseFormat responseFormat; + String ecompErrorContext = "delete service"; + Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext); + if (validateEmptyResult.isRight()) { + return validateEmptyResult.right().value(); + } + + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false); + if (eitherCreator.isRight()) { + return eitherCreator.right().value(); + } + user = eitherCreator.left().value(); + + Either<Service, ResponseFormat> getResult = getServiceByNameAndVersion(serviceName, version, user.getUserId()); + if (getResult.isRight()) { + return getResult.right().value(); + } + Service service = getResult.left().value(); + + StorageOperationStatus result = StorageOperationStatus.OK; + Either<Boolean, ResponseFormat> lockResult = lockComponent(service, "Mark service to delete"); + if (lockResult.isRight()) { + result = StorageOperationStatus.GENERAL_ERROR; + return componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + } + + try { + result = markComponentToDelete(service); + if (result.equals(StorageOperationStatus.OK)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT); + } else { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(result); + responseFormat = componentsUtils.getResponseFormatByResource(actionStatus, service.getName()); + } + return responseFormat; + + } finally { + if (result == null || !result.equals(StorageOperationStatus.OK)) { + log.warn("operation failed. do rollback"); + BeEcompErrorManager.getInstance().logBeSystemError("Delete Service"); + titanGenericDao.rollback(); + } else { + log.debug("operation success. do commit"); + titanGenericDao.commit(); + } + graphLockOperation.unlockComponent(service.getUniqueId(), NodeTypeEnum.Service); + } + } + + public Either<Service, ResponseFormat> getService(String serviceId, User user) { + String ecompErrorContext = "Get service"; + Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext); + if (validateEmptyResult.isRight()) { + return Either.right(validateEmptyResult.right().value()); + } + + Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + Either<Service, StorageOperationStatus> storageStatus = serviceOperation.getService(serviceId); + if (storageStatus.isRight()) { + log.debug("failed to get service by id {}", serviceId); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.SERVICE), serviceId)); + } + // Service service = + // createServiceApiArtifactLIst(storageStatus.left().value()); + Service service = storageStatus.left().value(); + return Either.left(service); + } + + public Either<Service, ResponseFormat> getServiceByNameAndVersion(String serviceName, String serviceVersion, String userId) { + Either<User, ResponseFormat> resp = validateUserExists(userId, "get Service By Name And Version", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + Either<Service, StorageOperationStatus> storageStatus = serviceOperation.getServiceByNameAndVersion(serviceName, serviceVersion, null, false); + if (storageStatus.isRight()) { + log.debug("failed to get service by name {} and version {}", serviceName, serviceVersion); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.SERVICE), serviceName)); + } + Service service = storageStatus.left().value(); + return Either.left(service); + } + + private void createMandatoryArtifactsData(Service service, User user) { + // create mandatory artifacts + + // TODO it must be removed after that artifact uniqueId creation will be + // moved to ArtifactOperation + // String serviceUniqueId = + // UniqueIdBuilder.buildServiceUniqueId(service.getComponentMetadataDefinition().getMetadataDataDefinition().getName(), + // service.getComponentMetadataDefinition().getMetadataDataDefinition().getVersion()); + String serviceUniqueId = service.getUniqueId(); + Map<String, ArtifactDefinition> artifactMap = service.getArtifacts(); + if (artifactMap == null) + artifactMap = new HashMap<String, ArtifactDefinition>(); + + Map<String, Object> informationalServiceArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getInformationalServiceArtifacts(); + List<String> exludeServiceCategory = ConfigurationManager.getConfigurationManager().getConfiguration().getExcludeServiceCategory(); + + String category = service.getCategories().get(0).getName(); + boolean isCreateArtifact = true; + if (category != null && exludeServiceCategory != null && !exludeServiceCategory.isEmpty()) { + for (String exlude : exludeServiceCategory) { + if (exlude.equalsIgnoreCase(category)) { + isCreateArtifact = false; + break; + } + } + + } + + if (informationalServiceArtifacts != null && isCreateArtifact) { + Set<String> keys = informationalServiceArtifacts.keySet(); + for (String informationalServiceArtifactName : keys) { + Map<String, Object> artifactInfoMap = (Map<String, Object>) informationalServiceArtifacts.get(informationalServiceArtifactName); + ArtifactDefinition artifactDefinition = createArtifactDefinition(serviceUniqueId, informationalServiceArtifactName, artifactInfoMap, user, false); + artifactMap.put(artifactDefinition.getArtifactLabel(), artifactDefinition); + + } + + service.setArtifacts(artifactMap); + } + } + + private ArtifactDefinition createArtifactDefinition(String serviceId, String logicalName, Map<String, Object> artifactInfoMap, User user, Boolean isServiceApi) { + + ArtifactDefinition artifactInfo = artifactsBusinessLogic.createArtifactPlaceHolderInfo(serviceId, logicalName, artifactInfoMap, user, ArtifactGroupTypeEnum.INFORMATIONAL); + + if (isServiceApi) { + artifactInfo.setMandatory(false); + artifactInfo.setServiceApi(true); + } + return artifactInfo; + } + + private Either<DistributionTransitionEnum, ResponseFormat> validateTransitionEnum(String distributionTransition, User user) { + DistributionTransitionEnum transitionEnum = null; + + transitionEnum = DistributionTransitionEnum.getFromDisplayName(distributionTransition); + if (transitionEnum == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Change Service Distribution"); + BeEcompErrorManager.getInstance().logBeSystemError("Change Service Distribution"); + log.info("state operation is not valid. operations allowed are: {}", DistributionTransitionEnum.valuesAsString()); + ResponseFormat error = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + return Either.right(error); + } + + return Either.left(transitionEnum); + } + + private Either<String, ResponseFormat> validateComment(LifecycleChangeInfoWithAction comment, User user, AuditingActionEnum auditAction) { + String data = comment.getUserRemarks(); + + if (data == null || data.trim().isEmpty()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "Change Service Distribution"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("Change Service Distribution"); + log.debug("user comment cannot be empty or null."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + data = ValidationUtils.removeNoneUtf8Chars(data); + data = ValidationUtils.removeHtmlTags(data); + data = ValidationUtils.normaliseWhitespace(data); + data = ValidationUtils.stripOctets(data); + + if (!ValidationUtils.validateLength(data, ValidationUtils.COMMENT_MAX_LENGTH)) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "Change Service Distribution"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("Change Service Distribution"); + log.debug("user comment exceeds limit."); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, "comment", String.valueOf(ValidationUtils.COMMENT_MAX_LENGTH))); + } + if (!ValidationUtils.validateIsEnglish(data)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + return Either.left(data); + } + + private Either<Service, ResponseFormat> validateServiceDistributionChange(User user, String serviceId, AuditingActionEnum auditAction, String comment) { + Either<Service, StorageOperationStatus> storageStatus = serviceOperation.getService(serviceId); + if (storageStatus.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.SERVICE_NOT_FOUND, serviceId); + createAudit(user, auditAction, comment, responseFormat); + return Either.right(responseFormat); + } + Service service = storageStatus.left().value(); + + if (service.getLifecycleState() != LifecycleStateEnum.CERTIFIED) { + log.info("service {} is not available for distribution. Should be in certified state", service.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, service.getVersion(), service.getName()); + createAudit(user, auditAction, comment, service, responseFormat); + return Either.right(responseFormat); + } + return Either.left(service); + } + + private Either<User, ResponseFormat> validateUserDistributionChange(User user, Service service, AuditingActionEnum auditAction, String comment) { + log.debug("get user from DB"); + /* + * Either<User, ActionStatus> eitherCreator = userAdmin.getUser(user.getUserId());s if (eitherCreator.isRight() || eitherCreator.left().value() == null) { BeEcompErrorManager.getInstance().processEcompError(EcompErrorName. BeUserMissingError, + * "Activate Distribution", user.getUserId()); log. debug("changeServiceDistributionState method - user is not listed. userId=" + user.getUserId()); ResponseFormat responseFormat = + * componentsUtils.getResponseFormat(ActionStatus.USER_NOT_FOUND); createAudit(user, auditAction, comment, responseFormat); return Either.right(responseFormat); } user = eitherCreator.left().value(); log.debug("validate user role"); if + * (!validateUserTemp(user, Role.ADMIN, Role.GOVERNOR)) { log.info("role {} is not allowed to perform this action", user.getRole()); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + * createAudit(user, auditAction, comment, service, responseFormat); return Either.right(responseFormat); } + */ + // get user details + Either<User, ResponseFormat> eitherCreator = validateUser(user, "Activate Distribution", service, auditAction, false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + user = eitherCreator.left().value(); + + // validate user role + List<Role> roles = new ArrayList<>(); + roles.add(Role.ADMIN); + roles.add(Role.GOVERNOR); + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, service, roles, auditAction, comment); + if (validateRes.isRight()) { + return Either.right(validateRes.right().value()); + } + return Either.left(user); + } + + private void createAudit(User user, AuditingActionEnum auditAction, String comment, ResponseFormat responseFormat) { + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + + createAudit(user, auditAction, comment, null, responseFormat, auditingFields); + } + + private void createAudit(User user, AuditingActionEnum auditAction, String comment, Service component, ResponseFormat responseFormat) { + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DCURR_STATUS, component.getDistributionStatus().name()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DPREV_STATUS, component.getDistributionStatus().name()); + createAudit(user, auditAction, comment, component, component.getLifecycleState().name(), component.getVersion(), responseFormat, auditingFields); + } + + private void createAudit(User user, AuditingActionEnum auditAction, String comment, Service component, ResponseFormat responseFormat, EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + log.debug("audit before sending response"); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, comment); + componentsUtils.auditComponent(responseFormat, user, component, null, null, auditAction, ComponentTypeEnum.SERVICE, auditingFields); + } + + private void createAudit(User user, AuditingActionEnum auditAction, String comment, Service component, String prevState, String prevVersion, ResponseFormat responseFormat, EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + log.debug("audit before sending response"); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, comment); + componentsUtils.auditComponent(responseFormat, user, component, prevState, prevVersion, auditAction, ComponentTypeEnum.SERVICE, auditingFields); + } + + public Either<Service, ResponseFormat> activateDistribution(String serviceId, String envName, User modifier, HttpServletRequest request) { + + Either<User, ResponseFormat> eitherCreator = validateUserExists(modifier.getUserId(), "activate Distribution", false); + if (eitherCreator.isRight()) { + return Either.right(eitherCreator.right().value()); + } + + User user = eitherCreator.left().value(); + + Either<Service, ResponseFormat> result = null; + ResponseFormat response = null; + Service updatedService = null; + String did = ThreadLocalsHolder.getUuid(); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, did); + // DE194021 + String configuredEnvName = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getEnvironments().get(0); + if (configuredEnvName != null && false == envName.equals(configuredEnvName)) { + log.trace("Update environment name to be {} instead of {}", configuredEnvName, envName); + envName = configuredEnvName; + } + // DE194021 + + ServletContext servletContext = request.getSession().getServletContext(); + boolean isDistributionEngineUp = getHealthCheckBL(servletContext).isDistributionEngineUp(request.getSession().getServletContext()); // DE + if (!isDistributionEngineUp) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Distribution Engine is DOWN"); + BeEcompErrorManager.getInstance().logBeSystemError("Distribution Engine is DOWN"); + log.debug("Distribution Engine is DOWN"); + response = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + return Either.right(response); + } + + Either<Service, StorageOperationStatus> serviceRes = serviceOperation.getService(serviceId); + if (serviceRes.isRight()) { + log.debug("failed retrieving service"); + response = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(serviceRes.right().value(), ComponentTypeEnum.SERVICE), serviceId); + componentsUtils.auditComponent(response, user, null, null, null, AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_REQUEST, ComponentTypeEnum.SERVICE, auditingFields); + return Either.right(response); + } + Service service = serviceRes.left().value(); + String dcurrStatus = service.getDistributionStatus().name(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DPREV_STATUS, dcurrStatus); + + Either<INotificationData, StorageOperationStatus> readyForDistribution = distributionEngine.isReadyForDistribution(service, did, envName); + if (readyForDistribution.isLeft()) { + INotificationData notificationData = readyForDistribution.left().value(); + StorageOperationStatus notifyServiceResponse = distributionEngine.notifyService(did, service, notificationData, envName, user.getUserId(), user.getFullName()); + if (notifyServiceResponse == StorageOperationStatus.OK) { + Either<Service, ResponseFormat> updateStateRes = updateDistributionStatusForActivation(service, user, DistributionStatusEnum.DISTRIBUTED); + if (updateStateRes.isLeft() && updateStateRes.left().value() != null) { + updatedService = updateStateRes.left().value(); + dcurrStatus = updatedService.getDistributionStatus().name(); + } else { + // The response is not relevant + updatedService = service; + } + ASDCKpiApi.countActivatedDistribution(); + response = componentsUtils.getResponseFormat(ActionStatus.OK); + result = Either.left(updatedService); + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Activate Distribution - send notification"); + BeEcompErrorManager.getInstance().logBeSystemError("Activate Distribution - send notification"); + log.debug("distributionEngine.notifyService response is: {}", notifyServiceResponse); + response = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + result = Either.right(response); + } + } else { + StorageOperationStatus distEngineValidationResponse = readyForDistribution.right().value(); + response = componentsUtils.getResponseFormatByDE(componentsUtils.convertFromStorageResponse(distEngineValidationResponse), service.getName(), envName); + result = Either.right(response); + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_DCURR_STATUS, dcurrStatus); + componentsUtils.auditComponent(response, user, service, null, null, AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_REQUEST, ComponentTypeEnum.SERVICE, auditingFields); + return result; + } + + // convert to private after deletion of temp url + public Either<Service, ResponseFormat> updateDistributionStatusForActivation(Service service, User user, DistributionStatusEnum state) { + + Either<User, ResponseFormat> resp = validateUserExists(user.getUserId(), "update Distribution Status For Activation", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + String serviceId = service.getUniqueId(); + Either<Boolean, ResponseFormat> lockResult = lockComponent(serviceId, service, "updateDistributionStatusForActivation"); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either<Service, StorageOperationStatus> result = serviceOperation.updateDestributionStatus(service, user, state); + if (result.isRight()) { + titanGenericDao.rollback(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "updateDistributionStatusForActivation"); + BeEcompErrorManager.getInstance().logBeSystemError("updateDistributionStatusForActivation"); + log.debug("service {} change distribution status failed", serviceId); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + titanGenericDao.commit(); + return Either.left(result.left().value()); + } finally { + graphLockOperation.unlockComponent(serviceId, NodeTypeEnum.Service); + } + } + + public Either<Service, ResponseFormat> markDistributionAsDeployed(String serviceId, String did, User user) { + + Either<User, ResponseFormat> resp = validateUserExists(user.getUserId(), "mark Distribution As Deployed", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + log.debug("mark distribution deployed"); + + AuditingActionEnum auditAction = AuditingActionEnum.DISTRIBUTION_DEPLOY; + Either<Service, StorageOperationStatus> getServiceResponse = serviceOperation.getService(serviceId); + if (getServiceResponse.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeServiceMissingError, "markDistributionAsDeployed", serviceId); + BeEcompErrorManager.getInstance().logBeComponentMissingError("markDistributionAsDeployed", ComponentTypeEnum.SERVICE.getValue(), serviceId); + log.debug("service {} not found", serviceId); + ResponseFormat responseFormat = auditDeployError(did, user, auditAction, null, componentsUtils.convertFromStorageResponse(getServiceResponse.right().value(), ComponentTypeEnum.SERVICE), ""); + + return Either.right(responseFormat); + } + + Service service = getServiceResponse.left().value(); + + Either<User, ResponseFormat> validateRoleForDeploy = validateRoleForDeploy(did, user, auditAction, service); + if (validateRoleForDeploy.isRight()) { + return Either.right(validateRoleForDeploy.right().value()); + } + user = validateRoleForDeploy.left().value(); + + return checkDistributionAndDeploy(did, user, auditAction, service); + + } + + public Either<Service, ResponseFormat> generateVfModuleArtifacts(Service service, User modifier, boolean shouldLock) { + Function<ComponentInstance, List<ArtifactGenerator<ArtifactDefinition>>> artifactTaskGeneratorCreator = ri -> + // Only one VF Module Artifact per instance - add it to a list of one + Arrays.asList(new VfModuleArtifacGenerator(modifier, ri, service, shouldLock)); + + return generateDeploymentArtifacts(service, modifier, artifactTaskGeneratorCreator); + + } + + private List<GroupDefinition> collectGroupsForCompInstance(ComponentInstance currVF, Wrapper<ResponseFormat> responseWrapper) { + List<GroupDefinition> relevantGroups = new ArrayList<>(); + Either<List<GroupDefinition>, StorageOperationStatus> eitherGroups = groupOperation.getAllGroups(currVF.getComponentUid(), NodeTypeEnum.Resource); + + if (eitherGroups.isRight()) { + final StorageOperationStatus storageStatus = eitherGroups.right().value(); + if (storageStatus != StorageOperationStatus.NOT_FOUND && storageStatus != StorageOperationStatus.OK) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageStatus); + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(actionStatus)); + } + + } else { + relevantGroups = eitherGroups.left().value().stream().filter(p -> GroupTypeEnum.VF_MODULE.getGroupTypeName().equals(p.getType())).collect(Collectors.toList()); + } + return relevantGroups; + } + + private ArtifactDefinition getVfModuleArtifactForCompInstance(ComponentInstance currVF, Service service, User modifier, List<GroupDefinition> groupsForCurrVF, Wrapper<String> payloadWrapper, Wrapper<ResponseFormat> responseWrapper) { + ArtifactDefinition vfModuleAertifact = null; + + Optional<ArtifactDefinition> optionalVfModuleArtifact = currVF.getDeploymentArtifacts().values().stream().filter(p -> p.getArtifactType().equals(ArtifactTypeEnum.VF_MODULES_METADATA.name())).findAny(); + if (optionalVfModuleArtifact.isPresent()) { + vfModuleAertifact = optionalVfModuleArtifact.get(); + } else { + Either<ArtifactDefinition, ResponseFormat> createVfModuleArtifact = createVfModuleArtifact(modifier, currVF, service, payloadWrapper.getInnerElement()); + if (createVfModuleArtifact.isLeft()) { + vfModuleAertifact = createVfModuleArtifact.left().value(); + } else { + responseWrapper.setInnerElement(createVfModuleArtifact.right().value()); + } + } + return vfModuleAertifact; + } + + private void fillVfModuleHeatEnvPayload(List<GroupDefinition> groupsForCurrVF, ComponentInstance currVFInstance, Wrapper<String> payloadWrapper) { + // Converts GroupDefinition to VfModuleArtifactPayload which is the + // format used in the payload + + List<VfModuleArtifactPayload> vfModulePayloadForCurrVF = groupsForCurrVF.stream().map(group -> new VfModuleArtifactPayload(group)).collect(Collectors.toList()); + Collections.sort(vfModulePayloadForCurrVF, (art1, art2) -> VfModuleArtifactPayload.compareByGroupName(art1, art2)); + // Update Payload With Heat Env + vfModulePayloadForCurrVF.stream().forEach(e -> addHeatEnvArtifactsToVFModulePayload(e, currVFInstance)); + + final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + String vfModulePayloadString = gson.toJson(vfModulePayloadForCurrVF); + payloadWrapper.setInnerElement(vfModulePayloadString); + + } + + private void addHeatEnvArtifactsToVFModulePayload(VfModuleArtifactPayload vfModulePayload, ComponentInstance currVFInstance) { + List<String> originalModuleArtifacts = vfModulePayload.getArtifacts(); + if (!MapUtils.isEmpty(currVFInstance.getDeploymentArtifacts()) && !CollectionUtils.isEmpty(originalModuleArtifacts)) { + + final Collection<ArtifactDefinition> depInsArtifacts = currVFInstance.getDeploymentArtifacts().values(); + // All Heat_ENV + List<ArtifactDefinition> heatEnvArtifacts = depInsArtifacts.stream().filter(art -> art.getArtifactType().equals(ArtifactTypeEnum.HEAT_ENV.getType())).collect(Collectors.toList()); + // Unique Id Of Artifacts In the vf module + List<String> moduleArtUniqueId = depInsArtifacts.stream().filter(art -> originalModuleArtifacts.contains(art.getArtifactUUID())).map(art -> art.getUniqueId()).collect(Collectors.toList()); + // Collect Only Heat Artifatcs that are Generated from artifacts in + // the module + List<String> relevantHeatEnvUUID = heatEnvArtifacts.stream().filter(heatEnv -> moduleArtUniqueId.contains(heatEnv.getGeneratedFromId())).map(heatEnv -> heatEnv.getArtifactUUID()).collect(Collectors.toList()); + + List<String> fullArtifactList = new ArrayList<>(); + fullArtifactList.addAll(originalModuleArtifacts); + fullArtifactList.addAll(relevantHeatEnvUUID); + + vfModulePayload.setArtifacts(fullArtifactList); + } + } + + private Either<ArtifactDefinition, ResponseFormat> generateVfModuleArtifact(User modifier, ComponentInstance currVFInstance, Service service, boolean shouldLock) { + ArtifactDefinition vfModuleAertifact = null; + Wrapper<ResponseFormat> responseWrapper = new Wrapper<>(); + Wrapper<String> payloadWrapper = new Wrapper<>(); + List<GroupDefinition> groupsForCurrVF = collectGroupsForCompInstance(currVFInstance, responseWrapper); + if (responseWrapper.isEmpty()) { + fillVfModuleHeatEnvPayload(groupsForCurrVF, currVFInstance, payloadWrapper); + } + if (responseWrapper.isEmpty()) { + vfModuleAertifact = getVfModuleArtifactForCompInstance(currVFInstance, service, modifier, groupsForCurrVF, payloadWrapper, responseWrapper); + } + if (responseWrapper.isEmpty() && vfModuleAertifact != null) { + vfModuleAertifact = fillVfModulePayload(modifier, currVFInstance, vfModuleAertifact, shouldLock, payloadWrapper, responseWrapper); + } + + Either<ArtifactDefinition, ResponseFormat> result; + if (responseWrapper.isEmpty()) { + result = Either.left(vfModuleAertifact); + } else { + result = Either.right(responseWrapper.getInnerElement()); + } + + return result; + } + + private ArtifactDefinition fillVfModulePayload(User modifier, ComponentInstance currVF, ArtifactDefinition vfModuleAertifact, boolean shouldLock, Wrapper<String> payloadWrapper, Wrapper<ResponseFormat> responseWrapper) { + ArtifactDefinition result = null; + final Either<Resource, StorageOperationStatus> eitherResource = resourceOperation.getResource(currVF.getComponentUid()); + if (eitherResource.isRight()) { + responseWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherResource.right().value()))); + } else { + Resource resource = eitherResource.left().value(); + Either<ArtifactDefinition, ResponseFormat> eitherPayload = artifactsBusinessLogic.generateArtifactPayload(vfModuleAertifact, resource, currVF.getName(), modifier, shouldLock, () -> System.currentTimeMillis(), + () -> Either.left(artifactsBusinessLogic.createEsArtifactData(vfModuleAertifact, payloadWrapper.getInnerElement().getBytes(StandardCharsets.UTF_8)))); + if (eitherPayload.isLeft()) { + result = eitherPayload.left().value(); + } else { + responseWrapper.setInnerElement(eitherPayload.right().value()); + } + } + + return result; + } + + private Either<ArtifactDefinition, ResponseFormat> createVfModuleArtifact(User modifier, ComponentInstance currVF, Service service, String vfModulePayloadString) { + + ArtifactDefinition vfModuleArtifactDefinition = new ArtifactDefinition(); + + vfModuleArtifactDefinition.setDescription("Auto-generated VF Modules information artifact"); + vfModuleArtifactDefinition.setArtifactDisplayName("Vf Modules Metadata"); + vfModuleArtifactDefinition.setArtifactType(ArtifactTypeEnum.VF_MODULES_METADATA.getType()); + vfModuleArtifactDefinition.setArtifactGroupType(ArtifactGroupTypeEnum.DEPLOYMENT); + vfModuleArtifactDefinition.setArtifactLabel("vfModulesMetadata"); + vfModuleArtifactDefinition.setTimeout(0); + vfModuleArtifactDefinition.setArtifactName(currVF.getNormalizedName() + "_modules.json"); + vfModuleArtifactDefinition.setPayloadData(vfModulePayloadString); + + Either<ArtifactDefinition, StorageOperationStatus> addArifactToComponent = artifactOperation.addArifactToComponent(vfModuleArtifactDefinition, currVF.getUniqueId(), NodeTypeEnum.ResourceInstance, true, true); + + Either<ArtifactDefinition, ResponseFormat> result; + if (addArifactToComponent.isLeft()) { + result = Either.left(addArifactToComponent.left().value()); + } else { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(addArifactToComponent.right().value()))); + } + + return result; + } + + public Either<Service, ResponseFormat> generateHeatEnvArtifacts(Service service, User modifier, boolean shouldLock) { + + Function<ComponentInstance, List<ArtifactGenerator<ArtifactDefinition>>> artifactTaskGeneratorCreator = resourceInstance -> + // Get All Deployment Artifacts + service.getComponentInstances().stream().filter(ri -> ri != null && ri == resourceInstance).filter(ri -> ri.getDeploymentArtifacts() != null).flatMap(ri -> ri.getDeploymentArtifacts().values().stream()). + // Filter in Only Heat Env + filter(depArtifact -> ArtifactTypeEnum.HEAT_ENV.getType().equals(depArtifact.getArtifactType())). + // Create ArtifactGenerator from those Artifacts + map(depArtifact -> new HeatEnvArtifactGenerator(depArtifact, service, resourceInstance.getName(), modifier, shouldLock)).collect(Collectors.toList()); + + return generateDeploymentArtifacts(service, modifier, artifactTaskGeneratorCreator); + + } + + private <CallVal> Either<Service, ResponseFormat> generateDeploymentArtifacts(Service service, User modifier, Function<ComponentInstance, List<ArtifactGenerator<CallVal>>> artifactTaskGeneratorCreator) { + + List<Future<Either<CallVal, ResponseFormat>>> allFutures = new ArrayList<>(); + + // Get Flat List of (Callable) ArtifactGenerator for all the RI in the + // service + if (service.getComponentInstances() != null) { + List<ArtifactGenerator<CallVal>> artifactGenList = service.getComponentInstances().stream().flatMap(ri -> artifactTaskGeneratorCreator.apply(ri).stream()).collect(Collectors.toList()); + if (artifactGenList != null && !artifactGenList.isEmpty()) { + ExecutorService executor = Executors.newFixedThreadPool(artifactGenList.size()); + + artifactGenList.stream().forEach(e -> allFutures.add(executor.submit(e))); + + boolean isSuccess = true; + ResponseFormat firstError = null; + for (Future<Either<CallVal, ResponseFormat>> entry : allFutures) { + try { + Either<CallVal, ResponseFormat> actionStatus = entry.get(20, TimeUnit.SECONDS); + if (actionStatus.isRight()) { + isSuccess = false; + if (firstError == null) { + firstError = actionStatus.right().value(); + } + log.debug("Failed to generate artifact error : {}", actionStatus.right().value()); + } + } catch (Exception e) { + log.debug("Failed to collect result from artifact generator ", e); + isSuccess = false; + firstError = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + } + } + executor.shutdown(); + if (!isSuccess) { + return Either.right(firstError); + } + } + + } + return Either.left(service); + } + + abstract class ArtifactGenerator<CallVal> implements Callable<Either<CallVal, ResponseFormat>> { + + } + + class HeatEnvArtifactGenerator extends ArtifactGenerator<ArtifactDefinition> { + ArtifactDefinition artifactDefinition; + Service service; + String resourceInstanceName; + User modifier; + boolean shouldLock; + + HeatEnvArtifactGenerator(ArtifactDefinition artifactDefinition, Service service, String resourceInstanceName, User modifier, boolean shouldLock) { + this.artifactDefinition = artifactDefinition; + this.service = service; + this.resourceInstanceName = resourceInstanceName; + this.modifier = modifier; + this.shouldLock = shouldLock; + } + + @Override + public Either<ArtifactDefinition, ResponseFormat> call() throws Exception { + return artifactsBusinessLogic.generateHeatEnvArtifact(artifactDefinition, service, resourceInstanceName, modifier, shouldLock); + } + + public ArtifactDefinition getArtifactDefinition() { + return artifactDefinition; + } + + } + + class VfModuleArtifacGenerator extends ArtifactGenerator<ArtifactDefinition> { + private User user; + private ComponentInstance componentInstance; + private Service service; + boolean shouldLock; + + @Override + public Either<ArtifactDefinition, ResponseFormat> call() throws Exception { + return generateVfModuleArtifact(user, componentInstance, service, shouldLock); + } + + private VfModuleArtifacGenerator(User user, ComponentInstance componentInstance, Service service, boolean shouldLock) { + super(); + this.user = user; + this.componentInstance = componentInstance; + this.service = service; + this.shouldLock = shouldLock; + } + + } + + private synchronized Either<Service, ResponseFormat> checkDistributionAndDeploy(String did, User user, AuditingActionEnum auditAction, Service service) { + boolean isDeployed = isDistributionDeployed(did, service); + if (isDeployed) { + return Either.left(service); + } + Either<Boolean, ResponseFormat> distributionSuccess = checkDistributionSuccess(did, user, auditAction, service); + if (distributionSuccess.isRight()) { + return Either.right(distributionSuccess.right().value()); + } + + log.debug("mark distribution {} as deployed - success", did); + componentsUtils.auditServiceDistributionDeployed(auditAction, service.getName(), service.getVersion(), service.getUUID(), did, STATUS_DEPLOYED, "OK", user); + return Either.left(service); + } + + private boolean isDistributionDeployed(String did, Service service) { + Either<List<DistributionDeployEvent>, ActionStatus> alreadyDeployed = auditCassandraDao.getDistributionDeployByStatus(did, AuditingActionEnum.DISTRIBUTION_DEPLOY.getName(), STATUS_DEPLOYED); + + boolean isDeployed = false; + if (alreadyDeployed.isLeft() && !alreadyDeployed.left().value().isEmpty()) { + // already deployed + log.debug("distribution {} is already deployed", did); + isDeployed = true; + } + return isDeployed; + } + + protected Either<Boolean, ResponseFormat> checkDistributionSuccess(String did, User user, AuditingActionEnum auditAction, Service service) { + + log.trace("checkDistributionSuccess"); + // get all "DRequest" records for this distribution + // Either<List<ESTimeBasedEvent>, ActionStatus> distRequestsResponse = + // auditingDao.getListOfDistributionByAction(did, + // AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_REQUEST.getName(), "", + // ResourceAdminEvent.class); + Either<List<ResourceAdminEvent>, ActionStatus> distRequestsResponse = auditCassandraDao.getDistributionRequest(did, AuditingActionEnum.DISTRIBUTION_STATE_CHANGE_REQUEST.getName()); + if (distRequestsResponse.isRight()) { + ResponseFormat error = auditDeployError(did, user, auditAction, service, distRequestsResponse.right().value()); + return Either.right(error); + } + + List<ResourceAdminEvent> distributionRequests = distRequestsResponse.left().value(); + if (distributionRequests.isEmpty()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionMissingError, "markDistributionAsDeployed", did); + BeEcompErrorManager.getInstance().logBeDistributionMissingError("markDistributionAsDeployed", did); + log.info("distribution {} is not found", did); + ResponseFormat error = auditDeployError(did, user, auditAction, service, ActionStatus.DISTRIBUTION_REQUESTED_NOT_FOUND); + return Either.right(error); + } + boolean isRequestSucceeded = false; + for (ResourceAdminEvent event : distributionRequests) { + String eventStatus = event.getStatus(); + if (eventStatus != null && eventStatus.equals(STATUS_SUCCESS_200)) { + isRequestSucceeded = true; + break; + } + } + + // get all "DNotify" records for this distribution + // Either<List<ESTimeBasedEvent>, ActionStatus> + // distNotificationsResponse = + // auditingDao.getListOfDistributionByAction(did, + // AuditingActionEnum.DISTRIBUTION_NOTIFY.getName(), "", + // DistributionNotificationEvent.class); + Either<List<DistributionNotificationEvent>, ActionStatus> distNotificationsResponse = auditCassandraDao.getDistributionNotify(did, AuditingActionEnum.DISTRIBUTION_NOTIFY.getName()); + if (distNotificationsResponse.isRight()) { + ResponseFormat error = auditDeployError(did, user, auditAction, service, distNotificationsResponse.right().value()); + return Either.right(error); + } + + List<DistributionNotificationEvent> distributionNotifications = distNotificationsResponse.left().value(); + boolean isNotificationsSucceeded = false; + for (DistributionNotificationEvent event : distributionNotifications) { + String eventStatus = event.getStatus(); + if (eventStatus != null && eventStatus.equals(STATUS_SUCCESS_200)) { + isNotificationsSucceeded = true; + break; + } + } + + // if request failed OR there are notifications that failed + if (!(isRequestSucceeded && isNotificationsSucceeded)) { + + log.info("distribution {} has failed", did); + ResponseFormat error = componentsUtils.getResponseFormat(ActionStatus.DISTRIBUTION_REQUESTED_FAILED, did); + auditDeployError(did, user, auditAction, service, ActionStatus.DISTRIBUTION_REQUESTED_FAILED, did); + return Either.right(error); + } + return Either.left(true); + } + + private ResponseFormat auditDeployError(String did, User user, AuditingActionEnum auditAction, Service service, ActionStatus status, String... params) { + + ResponseFormat error = componentsUtils.getResponseFormat(status, params); + String message = ""; + if (error.getMessageId() != null) { + message = error.getMessageId() + ": "; + } + message += error.getFormattedMessage(); + + if (service != null) { + componentsUtils.auditServiceDistributionDeployed(auditAction, service.getName(), service.getVersion(), service.getUUID(), did, error.getStatus().toString(), message, user); + } else { + componentsUtils.auditServiceDistributionDeployed(auditAction, "", "", "", did, error.getStatus().toString(), message, user); + } + return error; + } + + private Either<User, ResponseFormat> validateRoleForDeploy(String did, User user, AuditingActionEnum auditAction, Service service) { + Either<User, ActionStatus> eitherCreator = userAdmin.getUser(user.getUserId(), false); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUserMissingError, "Deploy Service", user.getUserId()); + BeEcompErrorManager.getInstance().logBeUserMissingError("Deploy Service", user.getUserId()); + log.debug("validateRoleForDeploy method - user is not listed. userId={}", user.getUserId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.USER_NOT_FOUND, user.getUserId()); + auditDeployError(did, user, auditAction, service, ActionStatus.USER_NOT_FOUND); + return Either.right(responseFormat); + } + user = eitherCreator.left().value(); + log.debug("validate user role"); + List<Role> roles = new ArrayList<>(); + roles.add(Role.ADMIN); + roles.add(Role.OPS); + Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, service, roles, auditAction, null); + if (validateRes.isRight()) { + log.info("role {} is not allowed to perform this action", user.getRole()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + auditDeployError(did, user, auditAction, service, ActionStatus.RESTRICTED_OPERATION); + return Either.right(responseFormat); + } + return Either.left(user); + + } + + @Override + public void setDeploymentArtifactsPlaceHolder(Component component, User user) { + // TODO Auto-generated method stub + + } + + @Override + public Either<List<String>, ResponseFormat> deleteMarkedComponents() { + return deleteMarkedComponents(ComponentTypeEnum.SERVICE); + } + + private HealthCheckBusinessLogic getHealthCheckBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + HealthCheckBusinessLogic healthCheckBl = webApplicationContext.getBean(HealthCheckBusinessLogic.class); + return healthCheckBl; + } + + @Override + public ComponentInstanceBusinessLogic getComponentInstanceBL() { + return serviceComponentInstanceBusinessLogic; + } + + @Override + public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, ComponentTypeEnum componentTypeEnum, String userId, String searchText) { + + Either<User, ResponseFormat> resp = validateUserExists(userId, "Get Component Instances", false); + if (resp.isRight()) { + return Either.right(resp.right().value()); + } + + ComponentOperation componentOperation = getComponentOperation(componentTypeEnum); + + Either<List<ComponentInstance>, StorageOperationStatus> componentInstancesResponse = componentOperation.getAllComponentInstncesMetadata(componentId, componentTypeEnum.getNodeType()); + if (componentInstancesResponse.isRight()) { + + if (componentInstancesResponse.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + return Either.left(new ArrayList<ComponentInstance>()); + } + ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentInstancesResponse.right().value())); + return Either.right(responseFormat); + } + + List<ComponentInstance> componentInstances = componentInstancesResponse.left().value(); + componentInstances = componentInstances.stream().filter(instance -> instance.getOriginType().equals(OriginTypeEnum.VF)).collect(Collectors.toList()); + + return Either.left(componentInstances); + } + + public ICacheMangerOperation getCacheManagerOperation() { + return cacheManagerOperation; + } + + public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) { + this.cacheManagerOperation = cacheManagerOperation; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceComponentInstanceBusinessLogic.java new file mode 100644 index 0000000000..c42cf004ff --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceComponentInstanceBusinessLogic.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("serviceComponentInstanceBusinessLogic") +public class ServiceComponentInstanceBusinessLogic extends ComponentInstanceBusinessLogic { + + @Override + protected Either<Boolean, ResponseFormat> validateAllowedToContainCompInstances(org.openecomp.sdc.be.model.Component containerComponent) { + return Either.left(true); + } + + @Override + protected NodeTypeEnum getNodeTypeOfComponentInstanceOrigin() { + return NodeTypeEnum.Resource; + } + + @Override + protected ComponentOperation getContainerComponentOperation() { + return serviceOperation; + } + + @Override + protected ComponentOperation getCompInstOriginComponentOperation() { + return resourceOperation; + } + + @Override + protected ComponentTypeEnum getComponentTypeOfComponentInstance() { + return ComponentTypeEnum.RESOURCE_INSTANCE; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/VFComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/VFComponentInstanceBusinessLogic.java new file mode 100644 index 0000000000..3e42897c79 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/VFComponentInstanceBusinessLogic.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("vfComponentInstanceBusinessLogic") +public class VFComponentInstanceBusinessLogic extends ComponentInstanceBusinessLogic { + + private static Logger log = LoggerFactory.getLogger(VFComponentInstanceBusinessLogic.class.getName()); + + @Override + protected Either<Boolean, ResponseFormat> validateAllowedToContainCompInstances(org.openecomp.sdc.be.model.Component containerComponent) { + Resource resource = (Resource) containerComponent; + ResourceTypeEnum resourceType = resource.getResourceType(); + if (ResourceTypeEnum.VF != resourceType) { + log.debug("Cannot attach resource instances to container resource of type {}", resourceType); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_CANNOT_CONTAIN_RESOURCE_INSTANCES, resourceType.getValue())); + } + return Either.left(true); + } + + @Override + protected NodeTypeEnum getNodeTypeOfComponentInstanceOrigin() { + return NodeTypeEnum.Resource; + } + + @Override + protected ComponentOperation getContainerComponentOperation() { + return resourceOperation; + } + + @Override + protected ComponentOperation getCompInstOriginComponentOperation() { + return resourceOperation; + } + + @Override + protected ComponentTypeEnum getComponentTypeOfComponentInstance() { + return ComponentTypeEnum.RESOURCE_INSTANCE; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java new file mode 100644 index 0000000000..445b3a9750 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java @@ -0,0 +1,209 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class CertificationChangeTransition extends LifeCycleTransition { + + private static Logger log = LoggerFactory.getLogger(CertificationChangeTransition.class.getName()); + + private LifecycleStateEnum nextState; + private LifeCycleTransitionEnum name; + private AuditingActionEnum auditingAction; + private ArtifactsBusinessLogic artifactsManager; + + public CertificationChangeTransition(LifeCycleTransitionEnum name, ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation) { + super(componentUtils, lifecycleOperation); + + this.name = name; + + // authorized roles + Role[] certificationChangeRoles = { Role.ADMIN, Role.TESTER }; + addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(certificationChangeRoles)); + addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(certificationChangeRoles)); + // TODO to be later defined for product + + switch (this.name) { + case CERTIFY: + this.auditingAction = AuditingActionEnum.CERTIFICATION_SUCCESS_RESOURCE; + this.nextState = LifecycleStateEnum.CERTIFIED; + break; + case FAIL_CERTIFICATION: + this.auditingAction = AuditingActionEnum.FAIL_CERTIFICATION_RESOURCE; + nextState = LifecycleStateEnum.NOT_CERTIFIED_CHECKIN; + break; + case CANCEL_CERTIFICATION: + this.auditingAction = AuditingActionEnum.CANCEL_CERTIFICATION_RESOURCE; + nextState = LifecycleStateEnum.READY_FOR_CERTIFICATION; + break; + default: + break; + } + + } + + @Override + public LifeCycleTransitionEnum getName() { + return name; + } + + @Override + public AuditingActionEnum getAuditingAction() { + return auditingAction; + } + + public ArtifactsBusinessLogic getArtifactsManager() { + return artifactsManager; + } + + public void setArtifactsManager(ArtifactsBusinessLogic artifactsManager) { + this.artifactsManager = artifactsManager; + } + + private ResponseFormat formatCertificationError(Component component, StorageOperationStatus response, ComponentTypeEnum componentType) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Change LifecycleState - Certify failed on graph"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Change LifecycleState - Certify failed on graph"); + log.debug("certification change failed on graph"); + + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(response); + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + return responseFormat; + } + + @Override + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(); + log.debug("validate before certification change. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId()); + + // validate user + Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo); + if (userValidationResponse.isRight()) { + return userValidationResponse; + } + + if (!oldState.equals(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, componentName, componentType.name().toLowerCase()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS) && !modifier.equals(owner) && !modifier.getRole().equals(Role.ADMIN.name())) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + return Either.left(true); + } + + @Override + public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) { + + log.info("start performing certification change for resource {}", component.getUniqueId()); + Either<? extends Component, ResponseFormat> result = null; + NodeTypeEnum nodeType = componentType.getNodeType(); + + try { + Either<? extends Component, StorageOperationStatus> certificationChangeResult = Either.right(StorageOperationStatus.GENERAL_ERROR); + if (nextState.equals(LifecycleStateEnum.CERTIFIED)) { + certificationChangeResult = lifeCycleOperation.certifyComponent(nodeType, component, modifier, owner, true); + } else { + certificationChangeResult = lifeCycleOperation.cancelOrFailCertification(nodeType, component, modifier, owner, nextState, true); + } + + if (certificationChangeResult.isRight()) { + ResponseFormat responseFormat = formatCertificationError(component, certificationChangeResult.right().value(), componentType); + result = Either.right(responseFormat); + return result; + } + + if (nextState.equals(LifecycleStateEnum.CERTIFIED)) { + Either<Boolean, StorageOperationStatus> deleteOldComponentVersions = lifeCycleOperation.deleteOldComponentVersions(nodeType, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(), + component.getComponentMetadataDefinition().getMetadataDataDefinition().getUUID(), true); + if (deleteOldComponentVersions.isRight()) { + ResponseFormat responseFormat = formatCertificationError(component, deleteOldComponentVersions.right().value(), componentType); + result = Either.right(responseFormat); + return result; + } + } + + result = Either.left(certificationChangeResult.left().value()); + return result; + } finally { + if (result == null || result.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Change LifecycleState"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Change LifecycleState"); + if (inTransaction == false) { + log.debug("operation failed. do rollback"); + lifeCycleOperation.getResourceOperation().getTitanGenericDao().rollback(); + } + } else { + if (inTransaction == false) { + log.debug("operation success. do commit"); + lifeCycleOperation.getResourceOperation().getTitanGenericDao().commit(); + } + } + } + + } + + public StorageOperationStatus deleteOldVersion(List<ArtifactDefinition> artifactsToDelete, Resource resourceToDelete) { + ResourceOperation resourceOperation = lifeCycleOperation.getResourceOperation(); + + Either<List<ArtifactDefinition>, StorageOperationStatus> artifactsRes = resourceOperation.getComponentArtifactsForDelete(resourceToDelete.getUniqueId(), NodeTypeEnum.Resource, true); + if (artifactsRes.isRight()) { + return artifactsRes.right().value(); + } + Either<Resource, StorageOperationStatus> deleteResourceRes = resourceOperation.deleteResource(resourceToDelete.getUniqueId(), true); + if (deleteResourceRes.isRight()) { + return deleteResourceRes.right().value(); + } + artifactsToDelete.addAll(artifactsRes.left().value()); + + return StorageOperationStatus.OK; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationRequestTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationRequestTransition.java new file mode 100644 index 0000000000..69a9cbdb24 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationRequestTransition.java @@ -0,0 +1,409 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; + +import org.openecomp.sdc.be.components.distribution.engine.ServiceDistributionArtifactsBuilder; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.CapabilityOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.tosca.ToscaExportHandler; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class CertificationRequestTransition extends LifeCycleTransition { + + private static Logger log = LoggerFactory.getLogger(CertificationRequestTransition.class.getName()); + + private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder; + private ResourceOperation resourceOperation; + private CapabilityOperation capabilityOperation; + private ServiceBusinessLogic serviceBusinessLogic; + private ToscaExportHandler toscaExportUtils; + + public CertificationRequestTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation, ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder, ServiceBusinessLogic serviceBusinessLogic, + CapabilityOperation capabilityOperation, ToscaExportHandler toscaExportUtils) { + super(componentUtils, lifecycleOperation); + + // authorized roles + Role[] resourceServiceCheckoutRoles = { Role.ADMIN, Role.DESIGNER }; + // Role[] productCheckoutRoles = {Role.ADMIN, Role.PRODUCT_MANAGER, + // Role.PRODUCT_STRATEGIST}; + addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(resourceServiceCheckoutRoles)); + // TODO to be later defined for product + // addAuthorizedRoles(ComponentTypeEnum.PRODUCT, + // Arrays.asList(productCheckoutRoles)); + + this.serviceDistributionArtifactsBuilder = serviceDistributionArtifactsBuilder; + if (lifeCycleOperation != null) + this.resourceOperation = lifeCycleOperation.getResourceOperation(); + this.serviceBusinessLogic = serviceBusinessLogic; + this.capabilityOperation = capabilityOperation; + this.toscaExportUtils = toscaExportUtils; + } + + @Override + public LifeCycleTransitionEnum getName() { + return LifeCycleTransitionEnum.CERTIFICATION_REQUEST; + } + + @Override + public AuditingActionEnum getAuditingAction() { + return AuditingActionEnum.CERTIFICATION_REQUEST_RESOURCE; + } + + protected Either<Boolean, ResponseFormat> validateAllResourceInstanceCertified(Component component) { + Either<Boolean, ResponseFormat> eitherResult = Either.left(true); + + List<ComponentInstance> resourceInstance = component.getComponentInstances(); + if (resourceInstance != null) { + Optional<ComponentInstance> nonCertifiedRIOptional = resourceInstance.stream().filter(p -> !ValidationUtils.validateCertifiedVersion(p.getComponentVersion())).findAny(); + // Uncertified Resource Found + if (nonCertifiedRIOptional.isPresent()) { + ComponentInstance nonCertifiedRI = nonCertifiedRIOptional.get(); + ResponseFormat resFormat = getRelevantResponseFormatUncertifiedRI(nonCertifiedRI, component.getComponentType()); + eitherResult = Either.right(resFormat); + } + } + return eitherResult; + } + + private ResponseFormat getRelevantResponseFormatUncertifiedRI(ComponentInstance nonCertifiedRI, ComponentTypeEnum componentType) { + + ResponseFormat responseFormat; + Either<Resource, StorageOperationStatus> eitherResource = resourceOperation.getResource(nonCertifiedRI.getComponentUid()); + if (eitherResource.isRight()) { + + responseFormat = componentUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + + } else { + ActionStatus actionStatus; + Resource resource = eitherResource.left().value(); + Either<List<Resource>, StorageOperationStatus> status = resourceOperation.findLastCertifiedResourceByUUID(resource); + + if (ValidationUtils.validateMinorVersion(nonCertifiedRI.getComponentVersion())) { + if (status.isRight() || status.left().value() == null || status.left().value().isEmpty()) { + actionStatus = ActionStatus.VALIDATED_RESOURCE_NOT_FOUND; + } else { + actionStatus = ActionStatus.FOUND_ALREADY_VALIDATED_RESOURCE; + } + } else { + if (status.isRight() || status.left().value() == null || status.left().value().isEmpty()) + actionStatus = ActionStatus.FOUND_LIST_VALIDATED_RESOURCES; + else { + actionStatus = ActionStatus.FOUND_ALREADY_VALIDATED_RESOURCE; + } + + } + String compType = (componentType == ComponentTypeEnum.RESOURCE) ? "VF" : "service"; + responseFormat = componentUtils.getResponseFormat(actionStatus, compType, resource.getName()); + } + return responseFormat; + } + + private Either<ActionStatus, Map<String, ArtifactDefinition>> validateMandatoryArtifactsSupplied(Map<String, ArtifactDefinition> artifacts) { + + if (artifacts == null || true == artifacts.isEmpty()) { + return Either.left(ActionStatus.OK); + } + + Map<String, ArtifactDefinition> invalidArtifacts = new HashMap<String, ArtifactDefinition>(); + for (Entry<String, ArtifactDefinition> artifact : artifacts.entrySet()) { + + ArtifactDefinition artifactDefinition = artifact.getValue(); + if (true == artifactDefinition.getMandatory()) { + String artifactEsId = artifactDefinition.getEsId(); + if (artifactEsId == null || true == artifactEsId.isEmpty()) { + invalidArtifacts.put(artifact.getKey(), artifactDefinition); + } + } + } + + if (true == invalidArtifacts.isEmpty()) { + return Either.left(ActionStatus.OK); + } else { + return Either.right(invalidArtifacts); + } + } + + @Override + public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) { + + log.debug("start performing certification request for resource {}", component.getUniqueId()); + + // Either<ActionStatus, Map<String, ArtifactDefinition>> + // validateMandatoryArtifacts = + // validateMandatoryArtifactsSupplied(component.getArtifacts()); + // log.debug("After checking mandatory artifacts were populated. Result + // is " + validateMandatoryArtifacts); + // if (validateMandatoryArtifacts.isRight()) { + // ResponseFormat responseFormat = componentUtils + // .getResponseFormatByMissingArtifacts( + // componentType, + // validateMandatoryArtifacts.right().value()); + // return Either.right(responseFormat); + // } + ActionStatus actionStatus = null; + ResponseFormat responseFormat = null; + + if (componentType == ComponentTypeEnum.SERVICE || (componentType == ComponentTypeEnum.RESOURCE && ((Resource) component).getResourceType() == ResourceTypeEnum.VF)) { + + Either<Boolean, ResponseFormat> statusCert = validateAllResourceInstanceCertified(component); + if (statusCert.isRight()) { + return Either.right(statusCert.right().value()); + } + + statusCert = validateConfiguredAtomicReqCapSatisfied(component); + if (statusCert.isRight()) { + return Either.right(statusCert.right().value()); + } + } + if (componentType == ComponentTypeEnum.SERVICE) { + Either<Boolean, StorageOperationStatus> status = validateDeloymentArtifactSupplied((Service) component); + if (status.isRight()) { + StorageOperationStatus operationStatus = status.right().value(); + actionStatus = componentUtils.convertFromStorageResponse(operationStatus); + } else { + Boolean isDeploymentArtifactExists = status.left().value(); + if (isDeploymentArtifactExists == null || isDeploymentArtifactExists.booleanValue() == false) { + actionStatus = ActionStatus.SERVICE_DEPLOYMENT_ARTIFACT_NOT_FOUND; + } else { + Either<Service, ResponseFormat> generateHeatEnvResult = serviceBusinessLogic.generateHeatEnvArtifacts((Service) component, modifier, shouldLock); + if (generateHeatEnvResult.isRight()) { + return Either.right(generateHeatEnvResult.right().value()); + } + Either<Service, ResponseFormat> generateVfModuleResult = serviceBusinessLogic.generateVfModuleArtifacts((Service) component, modifier, shouldLock); + if (generateVfModuleResult.isRight()) { + return Either.right(generateVfModuleResult.right().value()); + } + } + } + + if (actionStatus != null) { + responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + return Either.right(responseFormat); + } + + } + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> eitherPopulated = componentBl.populateToscaArtifacts(component, modifier, true, inTransaction, shouldLock); + if (eitherPopulated != null && eitherPopulated.isRight()) { + return Either.right(eitherPopulated.right().value()); + } + + NodeTypeEnum nodeType = (componentType.equals(ComponentTypeEnum.SERVICE)) ? NodeTypeEnum.Service : NodeTypeEnum.Resource; + Either<? extends Component, StorageOperationStatus> certificationRequestResult = lifeCycleOperation.requestCertificationComponent(nodeType, component, modifier, owner, inTransaction); + if (certificationRequestResult.isRight()) { + log.debug("checkout failed on graph"); + StorageOperationStatus response = certificationRequestResult.right().value(); + actionStatus = componentUtils.convertFromStorageResponse(response); + + if (response.equals(StorageOperationStatus.ENTITY_ALREADY_EXISTS)) { + actionStatus = ActionStatus.COMPONENT_VERSION_ALREADY_EXIST; + } + responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + return Either.right(responseFormat); + } + + return Either.left(certificationRequestResult.left().value()); + } + + private Either<Boolean, ResponseFormat> validateConfiguredAtomicReqCapSatisfied(Component component) { + log.debug("Submit for testing validation - Start validating configured req/cap satisfied for inner atomic instances, component id:{}", component.getUniqueId()); + List<ComponentInstance> componentInstances = component.getComponentInstances(); + if (componentInstances != null) { + // Prepare relationships data structures + // Better make it list than set in case we need to count req/cap + // occurrences in the future + Map<String, List<String>> reqName2Ids = new HashMap<>(); + Map<String, List<String>> capName2Ids = new HashMap<>(); + parseRelationsForReqCapVerification(component, reqName2Ids, capName2Ids); + Map<String, Set<String>> requirementsToFulfillBeforeCert = configurationManager.getConfiguration().getRequirementsToFulfillBeforeCert(); + Map<String, Set<String>> capabilitiesToConsumeBeforeCert = configurationManager.getConfiguration().getCapabilitiesToConsumeBeforeCert(); + for (ComponentInstance compInst : componentInstances) { + String compInstId = compInst.getUniqueId(); + OriginTypeEnum originType = compInst.getOriginType(); + if (originType == null) { + log.error("Origin type is not set for component instance {} - it shouldn't happen. Skipping this component instance...", compInst.getUniqueId()); + continue; + } + String compInstType = originType.getValue(); + // Validating configured requirements fulfilled + if (null != requirementsToFulfillBeforeCert) { + Set<String> reqToFulfillForType = requirementsToFulfillBeforeCert.get(compInstType); + if (reqToFulfillForType != null) { + for (String reqNameToFulfill : reqToFulfillForType) { + List<String> reqNameList = reqName2Ids.get(reqNameToFulfill); + if (reqNameList == null || !reqNameList.contains(compInstId)) { + log.debug("Requirement {} wasn't fulfilled for component instance {} of type {}", reqNameToFulfill, compInstId, compInstType); + ComponentTypeEnum componentType = component.getComponentType(); + String compParam = (componentType == ComponentTypeEnum.RESOURCE) ? "VF" : componentType.getValue().toLowerCase(); + ResponseFormat responseFormat = componentUtils.getResponseFormat(ActionStatus.REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, component.getName(), compParam, originType.getDisplayValue(), compInst.getName(), "requirement", + reqNameToFulfill, "fulfilled"); + return Either.right(responseFormat); + } + } + } + } + // Validating configured capabilities consumed + if (null != capabilitiesToConsumeBeforeCert) { + Set<String> capToConsumeForType = capabilitiesToConsumeBeforeCert.get(compInstType); + if (capToConsumeForType != null) { + for (String capNameToConsume : capToConsumeForType) { + List<String> capNameList = capName2Ids.get(capNameToConsume); + if (capNameList == null || !capNameList.contains(compInstId)) { + log.debug("Capability {} wasn't consumed for component instance {} of type {}", capNameToConsume, compInstId, compInstType); + ComponentTypeEnum componentType = component.getComponentType(); + String compParam = (componentType == ComponentTypeEnum.RESOURCE) ? "VF" : componentType.getValue().toLowerCase(); + ResponseFormat responseFormat = componentUtils.getResponseFormat(ActionStatus.REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, component.getName(), compParam, originType.getDisplayValue(), compInst.getName(), "capability", + capNameToConsume, "consumed"); + return Either.right(responseFormat); + } + } + } + } + } + } + log.debug("Submit for testing validation - validating configured req/cap satisfied for inner atomic instances finished successfully, component id:{}", component.getUniqueId()); + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> parseRelationsForReqCapVerification(Component component, Map<String, List<String>> reqName2Ids, Map<String, List<String>> capName2Ids) { + log.debug("Submit for testing validation - Preparing relations for inner atomic instances validation"); + List<RequirementCapabilityRelDef> componentInstancesRelations = component.getComponentInstancesRelations(); + if (componentInstancesRelations != null) { + for (RequirementCapabilityRelDef reqCapRelDef : componentInstancesRelations) { + List<RequirementAndRelationshipPair> relationships = reqCapRelDef.getRelationships(); + if (relationships != null) { + for (RequirementAndRelationshipPair reqRelPair : relationships) { + String capUniqueId = reqRelPair.getCapabilityUid(); + Either<CapabilityDefinition, StorageOperationStatus> capability = capabilityOperation.getCapability(capUniqueId); + if (capability.isRight()) { + log.error("Couldn't fetch capability by id {}", capUniqueId); + return Either.right(componentUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + String reqCapType = capability.left().value().getType(); + String capabilityOwnerId = reqRelPair.getCapabilityOwnerId(); + String requirementOwnerId = reqRelPair.getRequirementOwnerId(); + // Update req + List<String> reqIds = reqName2Ids.get(reqCapType); + if (reqIds == null) { + reqIds = new ArrayList<>(); + reqName2Ids.put(reqCapType, reqIds); + } + reqIds.add(requirementOwnerId); + // Update cap + List<String> capIds = capName2Ids.get(reqCapType); + if (capIds == null) { + capIds = new ArrayList<>(); + capName2Ids.put(reqCapType, capIds); + } + capIds.add(capabilityOwnerId); + } + } + } + log.debug("Parsed req for validation: {}, parsed cap for validation: {}", reqName2Ids, capName2Ids); + } else { + log.debug("There are no relations found for component {}", component.getUniqueId()); + } + return Either.left(true); + } + + @Override + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(); + log.debug("validate before certification request. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId()); + + // validate user + Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo); + if (userValidationResponse.isRight()) { + return userValidationResponse; + } + + // case of "atomic" checkin and certification request - modifier must be + // the owner + if (oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) && !modifier.equals(owner) && !modifier.getRole().equals(Role.ADMIN.name())) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_CHECKOUT_BY_ANOTHER_USER, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + // other states + if (oldState.equals(LifecycleStateEnum.CERTIFIED)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_ALREADY_CERTIFIED, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + if (oldState.equals(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + if (oldState.equals(LifecycleStateEnum.READY_FOR_CERTIFICATION)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + return Either.left(true); + } + + private Either<Boolean, StorageOperationStatus> validateDeloymentArtifactSupplied(Service service) { + + Either<Boolean, StorageOperationStatus> serviceContainsDeploymentArtifacts = this.serviceDistributionArtifactsBuilder.isServiceContainsDeploymentArtifacts(service); + + return serviceContainsDeploymentArtifacts; + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckinTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckinTransition.java new file mode 100644 index 0000000000..28227285f1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckinTransition.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.Arrays; + +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class CheckinTransition extends LifeCycleTransition { + + private static Logger log = LoggerFactory.getLogger(CheckinTransition.class.getName()); + + public CheckinTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation) { + super(componentUtils, lifecycleOperation); + + // authorized roles + Role[] resourceServiceCheckoutRoles = { Role.ADMIN, Role.DESIGNER }; + Role[] productCheckoutRoles = { Role.ADMIN, Role.PRODUCT_MANAGER }; + addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.PRODUCT, Arrays.asList(productCheckoutRoles)); + + } + + @Override + public LifeCycleTransitionEnum getName() { + return LifeCycleTransitionEnum.CHECKIN; + } + + @Override + public AuditingActionEnum getAuditingAction() { + return AuditingActionEnum.CHECKIN_RESOURCE; + } + + @Override + public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) { + log.debug("start performing checkin for {} {}", componentType.name(), component.getUniqueId()); + + NodeTypeEnum nodeType = componentType.getNodeType(); + Either<? extends Component, StorageOperationStatus> checkinResourceResult = lifeCycleOperation.checkinComponent(nodeType, component, modifier, owner, inTransaction); + if (checkinResourceResult.isRight()) { + log.debug("checkout failed on graph"); + StorageOperationStatus response = checkinResourceResult.right().value(); + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(response); + + if (response.equals(StorageOperationStatus.ENTITY_ALREADY_EXISTS)) { + actionStatus = ActionStatus.COMPONENT_VERSION_ALREADY_EXIST; + } + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + return Either.right(responseFormat); + } + + return Either.left(checkinResourceResult.left().value()); + } + + @Override + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(); + log.debug("validate before checkin. component name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId()); + + // validate user + Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo); + if (userValidationResponse.isRight()) { + return userValidationResponse; + } + + if (!oldState.equals(LifecycleStateEnum.READY_FOR_CERTIFICATION) && !oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_ALREADY_CHECKED_IN, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) && !modifier.equals(owner) && !modifier.getRole().equals(Role.ADMIN.name())) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_CHECKOUT_BY_ANOTHER_USER, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.READY_FOR_CERTIFICATION) && !modifier.equals(owner) && !modifier.getRole().equals(Role.ADMIN.name())) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + return Either.left(true); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java new file mode 100644 index 0000000000..a4e6bdb86c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.Arrays; + +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class CheckoutTransition extends LifeCycleTransition { + + private static final String PLACE_HOLDER_RESOURCE_TYPES = "validForResourceTypes"; + + private static Logger log = LoggerFactory.getLogger(CheckoutTransition.class.getName()); + + public CheckoutTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation) { + super(componentUtils, lifecycleOperation); + + // authorized roles + Role[] resourceServiceCheckoutRoles = { Role.ADMIN, Role.DESIGNER }; + Role[] productCheckoutRoles = { Role.ADMIN, Role.PRODUCT_MANAGER }; + addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.PRODUCT, Arrays.asList(productCheckoutRoles)); + + } + + @Override + public LifeCycleTransitionEnum getName() { + return LifeCycleTransitionEnum.CHECKOUT; + } + + @Override + public AuditingActionEnum getAuditingAction() { + return AuditingActionEnum.CHECKOUT_RESOURCE; + } + + @Override + public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) { + + log.debug("start performing {} for resource {}", getName().name(), component.getUniqueId()); + + if (componentBl != null) + componentBl.setDeploymentArtifactsPlaceHolder(component, modifier); + NodeTypeEnum nodeType = componentType.getNodeType(); + Either<? extends Component, StorageOperationStatus> checkoutResourceResult = lifeCycleOperation.checkoutComponent(nodeType, component, modifier, owner, inTransaction); + + if (checkoutResourceResult.isRight()) { + log.debug("checkout failed on graph"); + StorageOperationStatus response = checkoutResourceResult.right().value(); + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(response); + + if (response.equals(StorageOperationStatus.ENTITY_ALREADY_EXISTS)) { + actionStatus = ActionStatus.COMPONENT_VERSION_ALREADY_EXIST; + } + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + return Either.right(responseFormat); + } + + return Either.left(checkoutResourceResult.left().value()); + } + + @Override + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(); + log.debug("validate before checkout. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId()); + + // validate user + Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo); + if (userValidationResponse.isRight()) { + return userValidationResponse; + } + + // Disabled as of 1604 patch after discussing with Ella/Eli/Michael + + /* + * if (componentType == ComponentTypeEnum.PRODUCT){ Either<Boolean, ResponseFormat> productContactsEither = productContactsValidation((Product)component, modifier); if (productContactsEither.isRight()){ return productContactsEither; } } + */ + + // check resource is not locked by another user + if (oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_IN_CHECKOUT_STATE, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.READY_FOR_CERTIFICATION)) { + if (!modifier.getRole().equals(Role.DESIGNER.name()) && !modifier.getRole().equals(Role.ADMIN.name())) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + } + return Either.left(true); + } + + /* + * private Either<Boolean, ResponseFormat> productContactsValidation(Product product, User modifier) { // validate user Either<Boolean, ResponseFormat> eitherResponse = Either.left(true); String role = modifier.getRole(); if + * (UserRoleEnum.PRODUCT_MANAGER.getName().equals(role) || UserRoleEnum.PRODUCT_STRATEGIST.getName().equals(role)){ String userId = modifier.getUserId(); if (!product.getContacts().contains(userId)){ log. + * debug("User with userId {} cannot checkout product. userId not found in product contacts list" , userId); ResponseFormat responseFormat = componentUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); return Either.right(responseFormat); + * } else { log. trace("Found user userId {} in product contacts - checkout request validated" ); } } return eitherResponse; } + */ + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifeCycleTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifeCycleTransition.java new file mode 100644 index 0000000000..49d94dc80b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifeCycleTransition.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction.LifecycleChanceActionEnum; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.exception.ResponseFormat; + +import fj.data.Either; + +public abstract class LifeCycleTransition { + + protected ConfigurationManager configurationManager; + protected ILifecycleOperation lifeCycleOperation; + protected ComponentsUtils componentUtils; + + protected Map<ComponentTypeEnum, List<Role>> authorizedRoles; + + protected LifeCycleTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation) { + + // configurationManager = (ConfigurationManager) + // context.getAttribute(Constants.CONFIGURATION_MANAGER_ATTR); + // lifeCycleOperation = LifecycleOperation.getInstance(); + this.configurationManager = ConfigurationManager.getConfigurationManager(); + this.lifeCycleOperation = lifecycleOperation; + this.componentUtils = componentUtils; + this.authorizedRoles = new HashMap<>(); + + } + + public abstract LifeCycleTransitionEnum getName(); + + public abstract AuditingActionEnum getAuditingAction(); + + public ConfigurationManager getConfigurationManager() { + return configurationManager; + } + + public void setConfigurationManager(ConfigurationManager configurationManager) { + this.configurationManager = configurationManager; + } + + public ILifecycleOperation getLifeCycleOperation() { + return lifeCycleOperation; + } + + public void setLifeCycleOperation(ILifecycleOperation lifeCycleOperation) { + this.lifeCycleOperation = lifeCycleOperation; + } + + public List<Role> getAuthorizedRoles(ComponentTypeEnum componentType) { + return authorizedRoles.get(componentType); + } + + public void addAuthorizedRoles(ComponentTypeEnum componentType, List<Role> authorizedRoles) { + this.authorizedRoles.put(componentType, authorizedRoles); + } + + // + // public Either<? extends Component, ResponseFormat> + // changeState(ComponentTypeEnum componentType, Component component, + // ComponentBusinessLogic componentBl, User modifier, User owner){ + // return changeState(componentType, component, componentBl, modifier, + // owner, false); + // } + + public abstract Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean needLock, boolean inTransaction); + + public abstract Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo); + + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState) { + + return this.validateBeforeTransition(component, componentType, modifier, owner, oldState, null); + } + + /** + * getComponentOwner + * + * @param resource + * @return + */ + protected Either<User, ResponseFormat> getComponentOwner(Component component, ComponentTypeEnum componentType) { + + return getComponentOwner(component, componentType, false); + } + + protected Either<User, ResponseFormat> getComponentOwner(Component component, ComponentTypeEnum componentType, boolean inTransaction) { + + NodeTypeEnum nodeType = componentType.getNodeType(); + Either<User, StorageOperationStatus> resourceOwnerResult = getLifeCycleOperation().getComponentOwner(component.getUniqueId(), nodeType, inTransaction); + if (resourceOwnerResult.isRight()) { + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(componentUtils.convertFromStorageResponse(resourceOwnerResult.right().value()), component, componentType); + return Either.right(responseFormat); + } + return Either.left(resourceOwnerResult.left().value()); + } + + /** + * isUserValidForRequest + * + * @param modifier + * @param action + * TODO + * @return + */ + protected Either<Boolean, ResponseFormat> userRoleValidation(User modifier, ComponentTypeEnum componentType, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + + // validate user + if (getAuthorizedRoles(componentType).contains(Role.valueOf(modifier.getRole()))) { + return Either.left(true); + } + + // this is only when creating vfc/cp when import vf from csar - when we + // create resources from node type, we create need to change the state + // to certified + if (lifecycleChangeInfo != null && lifecycleChangeInfo.getAction() != null && lifecycleChangeInfo.getAction() == LifecycleChanceActionEnum.CREATE_FROM_CSAR) { + return Either.left(true); + } + + ResponseFormat responseFormat = componentUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + return Either.right(responseFormat); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleBusinessLogic.java new file mode 100644 index 0000000000..27709bb332 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleBusinessLogic.java @@ -0,0 +1,572 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.openecomp.sdc.be.components.distribution.engine.ServiceDistributionArtifactsBuilder; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.impl.ProductBusinessLogic; +import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.CapabilityOperation; +import org.openecomp.sdc.be.model.operations.impl.ProductOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.ServiceOperation; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.tosca.ToscaExportHandler; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; + +@org.springframework.stereotype.Component("lifecycleBusinessLogic") +public class LifecycleBusinessLogic { + + private static final String COMMENT = "comment"; + + @Autowired + private IGraphLockOperation graphLockOperation = null; + + @Autowired + private ArtifactsBusinessLogic artifactsBusinessLogic; + + @Autowired + private ResourceOperation resourceOperation; + + @Autowired + private ServiceOperation serviceOperation; + + @Autowired + private ProductOperation productOperation; + + @Autowired + private CapabilityOperation capabilityOperation; + + private static Logger log = LoggerFactory.getLogger(LifecycleBusinessLogic.class.getName()); + + @javax.annotation.Resource + private ComponentsUtils componentUtils; + + @javax.annotation.Resource + private ILifecycleOperation lifecycleOperation; + @javax.annotation.Resource + ArtifactsBusinessLogic artifactsManager; + + @javax.annotation.Resource + private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder; + + @javax.annotation.Resource + private ServiceBusinessLogic serviceBusinessLogic; + + @javax.annotation.Resource + private ResourceBusinessLogic resourceBusinessLogic; + + @javax.annotation.Resource + private ProductBusinessLogic productBusinessLogic; + + @Autowired + private ToscaExportHandler toscaExportUtils; + + @Autowired + ICacheMangerOperation cacheManagerOperation; + + private Map<String, LifeCycleTransition> stateTransitions; + private static volatile boolean isInitialized = false; + + @PostConstruct + public void init() { + // init parameters + if (!isInitialized) { + synchronized (this) { + if (!isInitialized) { + initStateOperations(); + isInitialized = true; + } + } + } + } + + private void initStateOperations() { + stateTransitions = new HashMap<String, LifeCycleTransition>(); + + LifeCycleTransition checkoutOp = new CheckoutTransition(componentUtils, lifecycleOperation); + stateTransitions.put(checkoutOp.getName().name(), checkoutOp); + + UndoCheckoutTransition undoCheckoutOp = new UndoCheckoutTransition(componentUtils, lifecycleOperation); + undoCheckoutOp.setArtifactsBusinessLogic(artifactsBusinessLogic); + stateTransitions.put(undoCheckoutOp.getName().name(), undoCheckoutOp); + + LifeCycleTransition checkinOp = new CheckinTransition(componentUtils, lifecycleOperation); + stateTransitions.put(checkinOp.getName().name(), checkinOp); + + LifeCycleTransition certificationRequest = new CertificationRequestTransition(componentUtils, lifecycleOperation, serviceDistributionArtifactsBuilder, serviceBusinessLogic, capabilityOperation, toscaExportUtils); + stateTransitions.put(certificationRequest.getName().name(), certificationRequest); + + LifeCycleTransition startCertification = new StartCertificationTransition(componentUtils, lifecycleOperation); + stateTransitions.put(startCertification.getName().name(), startCertification); + + LifeCycleTransition failCertification = new CertificationChangeTransition(LifeCycleTransitionEnum.FAIL_CERTIFICATION, componentUtils, lifecycleOperation); + stateTransitions.put(failCertification.getName().name(), failCertification); + + LifeCycleTransition cancelCertification = new CertificationChangeTransition(LifeCycleTransitionEnum.CANCEL_CERTIFICATION, componentUtils, lifecycleOperation); + stateTransitions.put(cancelCertification.getName().name(), cancelCertification); + + CertificationChangeTransition successCertification = new CertificationChangeTransition(LifeCycleTransitionEnum.CERTIFY, componentUtils, lifecycleOperation); + successCertification.setArtifactsManager(artifactsBusinessLogic); + stateTransitions.put(successCertification.getName().name(), successCertification); + } + + public LifeCycleTransition getLifecycleTransition(LifeCycleTransitionEnum transitionEnum) { + return stateTransitions.get(transitionEnum.name()); + } + + public Either<Service, ResponseFormat> changeServiceState(String serviceId, User modifier, LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction, boolean needLock) { + return (Either<Service, ResponseFormat>) changeComponentState(ComponentTypeEnum.SERVICE, serviceId, modifier, transitionEnum, changeInfo, inTransaction, needLock); + } + + // TODO: rhalili - should use changeComponentState when possible + public Either<Resource, ResponseFormat> changeState(String resourceId, User modifier, LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction, boolean needLock) { + return (Either<Resource, ResponseFormat>) changeComponentState(ComponentTypeEnum.RESOURCE, resourceId, modifier, transitionEnum, changeInfo, inTransaction, needLock); + + // LifeCycleTransition lifeCycleTransition = + // stateTransitions.get(transitionEnum.name()); + // if (lifeCycleTransition == null) { + // log.debug("state operation is not valid. operations allowed are: {}", + // LifeCycleTransitionEnum.valuesAsString()); + // ResponseFormat error = + // componentUtils.getInvalidContentErrorAndAudit(modifier, + // AuditingActionEnum.CHECKOUT_RESOURCE); + // return Either.right(error); + // } + // + // Either<Resource, ResponseFormat> operationResult; + // Resource resource = null; + // boolean needToUnlockResource = false; + // + // log.debug("get resource from graph"); + // ResponseFormat errorResponse; + // Either<Resource, ResponseFormat> eitherResourceResponse = + // getResourceForChange(resourceId, modifier, lifeCycleTransition); + // if (eitherResourceResponse.isRight()) { + // return eitherResourceResponse; + // } + // resource = eitherResourceResponse.left().value(); + // String resourceCurrVersion = resource.getResourceVersion(); + // LifecycleStateEnum resourceCurrState = resource.getLifecycleState(); + // + // if (inTransaction == false) { + // // lock resource + // Either<Boolean, ResponseFormat> eitherLockResource = + // lockResource(resource); + // if (eitherLockResource.isRight()) { + // errorResponse = eitherLockResource.right().value(); + // componentUtils.auditResource(errorResponse, modifier, resource, + // resourceCurrState.name(), resourceCurrVersion, + // lifeCycleTransition.getAuditingAction(), null); + // return Either.right(errorResponse); + // } + // needToUnlockResource = true; + // } + // + // try { + // Either<Boolean, ResponseFormat> resourceNotDeleted = + // validateResourceNotDeleted(modifier, lifeCycleTransition, resource, + // resourceCurrVersion); + // if (resourceNotDeleted.isRight()) { + // return Either.right(resourceNotDeleted.right().value()); + // } + // + // Either<Boolean, ResponseFormat> validateHighestVersion = + // validateHighestVersion(modifier, lifeCycleTransition, resource, + // resourceCurrVersion); + // if (validateHighestVersion.isRight()) { + // return Either.right(validateHighestVersion.right().value()); + // } + // + // Either<User, ResponseFormat> ownerResult = + // lifeCycleTransition.getResourceOwner(resource); + // if (ownerResult.isRight()) { + // return Either.right(ownerResult.right().value()); + // } + // User owner = ownerResult.left().value(); + // log.debug("owner of resource {} is {}", resource.getUniqueId(), + // owner.getUserId()); + // + // LifecycleStateEnum oldState = resource.getLifecycleState(); + // + // Either<String, ResponseFormat> commentValidationResult = + // validateComment(changeInfo, transitionEnum); + // if (commentValidationResult.isRight()) { + // errorResponse = commentValidationResult.right().value(); + // EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new + // EnumMap<AuditingFieldsKeysEnum, + // Object>(AuditingFieldsKeysEnum.class); + // auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, + // changeInfo.getUserRemarks()); + // componentUtils.auditResource(errorResponse, modifier, resource, + // resourceCurrState.name(), resourceCurrVersion, + // lifeCycleTransition.getAuditingAction(), auditingFields); + // return Either.right(errorResponse); + // } + // changeInfo.setUserRemarks(commentValidationResult.left().value()); + // + // Either<Boolean, ResponseFormat> stateValidationResult = + // lifeCycleTransition.validateResourceBeforeTransition(resource.getResourceName(), + // ComponentTypeEnum.RESOURCE, modifier, owner, oldState); + // if (stateValidationResult.isRight()) { + // errorResponse = stateValidationResult.right().value(); + // componentUtils.auditResource(errorResponse, modifier, resource, + // resourceCurrState.name(), resourceCurrVersion, + // lifeCycleTransition.getAuditingAction(), null); + // return Either.right(errorResponse); + // } + // + // operationResult = lifeCycleTransition.changeStateOperation(resource, + // modifier, owner, inTransaction); + // + // if (operationResult.isRight()) { + // errorResponse = operationResult.right().value(); + // log.debug("audit before sending response"); + // componentUtils.auditResource(errorResponse, modifier, resource, + // resourceCurrState.name(), resourceCurrVersion, + // lifeCycleTransition.getAuditingAction(), null); + // + // return Either.right(errorResponse); + // } + // Resource resourceAfterOperation = operationResult.left().value(); + // EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new + // EnumMap<AuditingFieldsKeysEnum, + // Object>(AuditingFieldsKeysEnum.class); + // auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, + // changeInfo.getUserRemarks()); + // componentUtils.auditResource(componentUtils.getResponseFormat(ActionStatus.OK), + // modifier, resourceAfterOperation, resourceCurrState.name(), + // resourceCurrVersion, lifeCycleTransition.getAuditingAction(), + // auditingFields); + // return operationResult; + // + // } finally { + // log.debug("unlock resource {}", resourceId); + // if (needToUnlockResource && resource != null) { + // resource.setUniqueId(resourceId); + // graphLockOperation.unlockResource(resource); + // } + // } + + } + + public Either<? extends Component, ResponseFormat> changeComponentState(ComponentTypeEnum componentType, String componentId, User modifier, LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction, + boolean needLock) { + + LifeCycleTransition lifeCycleTransition = stateTransitions.get(transitionEnum.name()); + if (lifeCycleTransition == null) { + log.debug("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString()); + ResponseFormat error = componentUtils.getInvalidContentErrorAndAudit(modifier, AuditingActionEnum.CHECKOUT_RESOURCE); + return Either.right(error); + } + ComponentBusinessLogic bl = getComponentBL(componentType); + + Either<? extends Component, ResponseFormat> operationResult = null; + Component component = null; + // boolean needToUnlockResource = false; + log.debug("get resource from graph"); + ResponseFormat errorResponse; + + Either<? extends Component, ResponseFormat> eitherResourceResponse = getComponentForChange(componentType, componentId, modifier, lifeCycleTransition, changeInfo); + if (eitherResourceResponse.isRight()) { + return eitherResourceResponse; + } + component = eitherResourceResponse.left().value(); + String resourceCurrVersion = component.getVersion(); + LifecycleStateEnum resourceCurrState = component.getLifecycleState(); + + // lock resource + if (inTransaction == false && needLock) { + Either<Boolean, ResponseFormat> eitherLockResource = lockComponent(componentType, component); + if (eitherLockResource.isRight()) { + errorResponse = eitherLockResource.right().value(); + componentUtils.auditComponent(errorResponse, modifier, component, resourceCurrState.name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), componentType, null); + return Either.right(errorResponse); + } + // needToUnlockResource = true; + } + try { + Either<String, ResponseFormat> commentValidationResult = validateComment(changeInfo, transitionEnum); + if (commentValidationResult.isRight()) { + errorResponse = commentValidationResult.right().value(); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, changeInfo.getUserRemarks()); + componentUtils.auditComponent(errorResponse, modifier, component, resourceCurrState.name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), componentType, auditingFields); + return Either.right(errorResponse); + } + changeInfo.setUserRemarks(commentValidationResult.left().value()); + + Either<Boolean, ResponseFormat> validateHighestVersion = validateHighestVersion(modifier, lifeCycleTransition, component, resourceCurrVersion, componentType); + if (validateHighestVersion.isRight()) { + return Either.right(validateHighestVersion.right().value()); + } + + Either<User, ResponseFormat> ownerResult = lifeCycleTransition.getComponentOwner(component, componentType, inTransaction); + if (ownerResult.isRight()) { + return Either.right(ownerResult.right().value()); + } + User owner = ownerResult.left().value(); + log.debug("owner of resource {} is {}", component.getUniqueId(), owner.getUserId()); + + LifecycleStateEnum oldState = component.getLifecycleState(); + + Either<Boolean, ResponseFormat> stateValidationResult = lifeCycleTransition.validateBeforeTransition(component, componentType, modifier, owner, oldState, changeInfo); + if (stateValidationResult.isRight()) { + errorResponse = stateValidationResult.right().value(); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, changeInfo.getUserRemarks()); + componentUtils.auditComponent(errorResponse, modifier, component, resourceCurrState.name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), componentType, auditingFields); + return Either.right(errorResponse); + + } + + operationResult = lifeCycleTransition.changeState(componentType, component, bl, modifier, owner, false, inTransaction); + + if (operationResult.isRight()) { + errorResponse = operationResult.right().value(); + log.debug("audit before sending response"); + componentUtils.auditComponentAdmin(errorResponse, modifier, component, resourceCurrState.name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), componentType); + + return Either.right(errorResponse); + } + Component resourceAfterOperation = operationResult.left().value(); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, changeInfo.getUserRemarks()); + componentUtils.auditComponent(componentUtils.getResponseFormat(ActionStatus.OK), modifier, resourceAfterOperation, resourceCurrState.name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), componentType, auditingFields); + return operationResult; + + } finally { + log.debug("unlock component {}", componentId); + if (inTransaction == false && needLock && component != null) { + component.setUniqueId(componentId); + NodeTypeEnum nodeType = componentType.getNodeType(); + + // Handle component change in the cache of the side affect of + // the operation + if (operationResult != null && operationResult.isLeft()) { + Component componentAfterOpertion = operationResult.left().value(); + String uniqueId = componentAfterOpertion.getUniqueId(); + if (false == componentId.equals(uniqueId)) { + log.debug("During change state, another component {} has been created/updated", uniqueId); + if (uniqueId != null) { + cacheManagerOperation.updateComponentInCache(uniqueId, componentAfterOpertion.getLastUpdateDate(), nodeType); + } + } + } + + graphLockOperation.unlockComponent(componentId, nodeType); + + } + } + + } + + private Either<? extends Component, ResponseFormat> getComponentForChange(ComponentTypeEnum componentType, String componentId, User modifier, LifeCycleTransition lifeCycleTransition, LifecycleChangeInfoWithAction changeInfo) { + + Either<? extends Component, StorageOperationStatus> eitherResourceResponse = Either.right(StorageOperationStatus.GENERAL_ERROR); + switch (componentType) { + case SERVICE: + eitherResourceResponse = serviceOperation.getComponent(componentId, true); + break; + case PRODUCT: + eitherResourceResponse = productOperation.getComponent(componentId, true); + break; + case RESOURCE: + eitherResourceResponse = resourceOperation.getComponent(componentId, true); + break; + default: + break; + } + + ResponseFormat errorResponse = null; + if (eitherResourceResponse.isRight()) { + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(eitherResourceResponse.right().value(), componentType); + errorResponse = componentUtils.getResponseFormat(actionStatus, Constants.EMPTY_STRING); + log.debug("audit before sending response"); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_COMMENT, changeInfo.getUserRemarks()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, componentId); + componentUtils.auditComponent(errorResponse, modifier, null, Constants.EMPTY_STRING, Constants.EMPTY_STRING, lifeCycleTransition.getAuditingAction(), componentType, auditingFields); + + return Either.right(errorResponse); + } + return Either.left(eitherResourceResponse.left().value()); + } + + private Either<Boolean, ResponseFormat> validateHighestVersion(User modifier, LifeCycleTransition lifeCycleTransition, Resource resource, String resourceCurrVersion) { + ResponseFormat errorResponse; + if (!resource.isHighestVersion()) { + log.debug("resource version {} is not the last version of resource {}", resource.getVersion(), resource.getName()); + errorResponse = componentUtils.getResponseFormat(ActionStatus.COMPONENT_HAS_NEWER_VERSION, resource.getName(), ComponentTypeEnum.RESOURCE.name().toLowerCase()); + componentUtils.auditResource(errorResponse, modifier, resource, resource.getLifecycleState().name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), null); + return Either.right(errorResponse); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateResourceNotDeleted(User modifier, LifeCycleTransition lifeCycleTransition, Resource resource, String resourceCurrVersion) { + + ResponseFormat errorResponse; + if ((resource.getIsDeleted() != null) && (resource.getIsDeleted() == true)) { + ActionStatus actionStatus = ActionStatus.RESOURCE_NOT_FOUND; + errorResponse = componentUtils.getResponseFormatByResource(actionStatus, resource.getName()); + log.debug("resource {} {} is marked for delete", resource.getName(), resource.getVersion()); + componentUtils.auditResource(errorResponse, modifier, null, "", "", lifeCycleTransition.getAuditingAction(), null); + + return Either.right(errorResponse); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> validateHighestVersion(User modifier, LifeCycleTransition lifeCycleTransition, Component component, String resourceCurrVersion, ComponentTypeEnum componentType) { + ResponseFormat errorResponse; + if (!component.isHighestVersion()) { + log.debug("Component version {} is not the last version of component {}", component.getComponentMetadataDefinition().getMetadataDataDefinition().getVersion(), + component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + errorResponse = componentUtils.getResponseFormat(ActionStatus.COMPONENT_HAS_NEWER_VERSION, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(), componentType.getValue().toLowerCase()); + componentUtils.auditComponentAdmin(errorResponse, modifier, component, component.getLifecycleState().name(), resourceCurrVersion, lifeCycleTransition.getAuditingAction(), componentType); + return Either.right(errorResponse); + } + return Either.left(true); + } + + private Either<Boolean, ResponseFormat> lockComponent(ComponentTypeEnum componentType, Component component) { + NodeTypeEnum nodeType = componentType.getNodeType(); + StorageOperationStatus lockResourceStatus = graphLockOperation.lockComponent(component.getUniqueId(), nodeType); + + if (lockResourceStatus.equals(StorageOperationStatus.OK)) { + return Either.left(true); + } else { + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(lockResourceStatus); + ResponseFormat responseFormat = componentUtils.getResponseFormat(actionStatus, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + return Either.right(responseFormat); + } + + } + + private Either<Resource, ResponseFormat> getResourceForChange(String resourceId, User modifier, LifeCycleTransition lifeCycleTransition) { + Either<Resource, StorageOperationStatus> eitherResourceResponse = resourceOperation.getResource(resourceId, true); + + ResponseFormat errorResponse = null; + if (eitherResourceResponse.isRight()) { + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(eitherResourceResponse.right().value()); + errorResponse = componentUtils.getResponseFormatByResource(actionStatus, ""); + log.debug("audit before sending response"); + // For audit of not found, resourceName should be uniqueID according + // to Ella + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceId); + componentUtils.auditResource(errorResponse, modifier, null, "", "", lifeCycleTransition.getAuditingAction(), null); + + return Either.right(errorResponse); + } + Resource resource = eitherResourceResponse.left().value(); + + return Either.left(resource); + + } + + private Either<String, ResponseFormat> validateComment(LifecycleChangeInfoWithAction changeInfo, LifeCycleTransitionEnum transitionEnum) { + String comment = changeInfo.getUserRemarks(); + if (LifeCycleTransitionEnum.CANCEL_CERTIFICATION == transitionEnum || LifeCycleTransitionEnum.CERTIFY == transitionEnum || LifeCycleTransitionEnum.FAIL_CERTIFICATION == transitionEnum || LifeCycleTransitionEnum.CHECKIN == transitionEnum + || LifeCycleTransitionEnum.CERTIFICATION_REQUEST == transitionEnum + // import? + ) { + + if (!ValidationUtils.validateStringNotEmpty(comment)) { + log.debug("user comment cannot be empty or null."); + ResponseFormat errorResponse = componentUtils.getResponseFormat(ActionStatus.MISSING_DATA, COMMENT); + return Either.right(errorResponse); + } + + comment = ValidationUtils.removeNoneUtf8Chars(comment); + comment = ValidationUtils.removeHtmlTags(comment); + comment = ValidationUtils.normaliseWhitespace(comment); + comment = ValidationUtils.stripOctets(comment); + + if (!ValidationUtils.validateLength(comment, ValidationUtils.COMMENT_MAX_LENGTH)) { + log.debug("user comment exceeds limit."); + return Either.right(componentUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, COMMENT, String.valueOf(ValidationUtils.COMMENT_MAX_LENGTH))); + } + if (!ValidationUtils.validateIsEnglish(comment)) { + return Either.right(componentUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + } + return Either.left(comment); + } + + private ComponentBusinessLogic getComponentBL(ComponentTypeEnum componentTypeEnum) { + ComponentBusinessLogic businessLogic; + switch (componentTypeEnum) { + case RESOURCE: { + businessLogic = this.resourceBusinessLogic; + break; + } + case SERVICE: { + businessLogic = this.serviceBusinessLogic; + break; + } + case PRODUCT: { + businessLogic = this.productBusinessLogic; + break; + } + + default: { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "getComponentBL"); + throw new IllegalArgumentException("Illegal component type:" + componentTypeEnum.getValue()); + } + } + return businessLogic; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleChangeInfoBase.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleChangeInfoBase.java new file mode 100644 index 0000000000..0c35caf41b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleChangeInfoBase.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +public class LifecycleChangeInfoBase { + + public LifecycleChangeInfoBase() { + } + + public LifecycleChangeInfoBase(String userRemarks) { + super(); + this.userRemarks = userRemarks; + } + + private String userRemarks; + + public String getUserRemarks() { + return userRemarks; + } + + public void setUserRemarks(String userRemarks) { + this.userRemarks = userRemarks; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleChangeInfoWithAction.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleChangeInfoWithAction.java new file mode 100644 index 0000000000..170e187f15 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/LifecycleChangeInfoWithAction.java @@ -0,0 +1,50 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +public class LifecycleChangeInfoWithAction extends LifecycleChangeInfoBase { + + public enum LifecycleChanceActionEnum { + CREATE_FROM_CSAR, UPDATE_FROM_EXTERNAL_API + }; + + private LifecycleChanceActionEnum action; + + public LifecycleChangeInfoWithAction() { + } + + public LifecycleChangeInfoWithAction(String userRemarks) { + super(userRemarks); + } + + public LifecycleChangeInfoWithAction(String userRemarks, LifecycleChanceActionEnum action) { + super(userRemarks); + this.action = action; + } + + public LifecycleChanceActionEnum getAction() { + return action; + } + + public void setAction(LifecycleChanceActionEnum action) { + this.action = action; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/StartCertificationTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/StartCertificationTransition.java new file mode 100644 index 0000000000..918140b0af --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/StartCertificationTransition.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.Arrays; + +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class StartCertificationTransition extends LifeCycleTransition { + + private static Logger log = LoggerFactory.getLogger(StartCertificationTransition.class.getName()); + + public StartCertificationTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation) { + super(componentUtils, lifecycleOperation); + + // authorized roles + Role[] rsrcServiceStartCertificationRoles = { Role.ADMIN, Role.TESTER }; + addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(rsrcServiceStartCertificationRoles)); + addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(rsrcServiceStartCertificationRoles)); + // TODO to be later defined for product + } + + @Override + public LifeCycleTransitionEnum getName() { + return LifeCycleTransitionEnum.START_CERTIFICATION; + } + + @Override + public AuditingActionEnum getAuditingAction() { + return AuditingActionEnum.START_CERTIFICATION_RESOURCE; + } + + @Override + public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) { + + log.debug("start performing certification test for resource {}", component.getUniqueId()); + + NodeTypeEnum nodeType = (componentType.equals(ComponentTypeEnum.SERVICE)) ? NodeTypeEnum.Service : NodeTypeEnum.Resource; + Either<? extends Component, StorageOperationStatus> stateChangeResult = lifeCycleOperation.startComponentCertification(nodeType, component, modifier, owner, inTransaction); + if (stateChangeResult.isRight()) { + log.debug("start certification failed on graph"); + StorageOperationStatus response = stateChangeResult.right().value(); + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(response); + + if (response.equals(StorageOperationStatus.ENTITY_ALREADY_EXISTS)) { + actionStatus = ActionStatus.COMPONENT_VERSION_ALREADY_EXIST; + } + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + return Either.right(responseFormat); + } + + return Either.left(stateChangeResult.left().value()); + } + + @Override + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(); + log.debug("validate before start certification test. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId()); + + // validate user + Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo); + if (userValidationResponse.isRight()) { + return userValidationResponse; + } + + if (oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN) || oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, componentName, componentType.name().toLowerCase()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.CERTIFIED)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_ALREADY_CERTIFIED, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + if (oldState.equals(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + return Either.left(true); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java new file mode 100644 index 0000000000..fcb211bc3e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java @@ -0,0 +1,170 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.lifecycle; + +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class UndoCheckoutTransition extends LifeCycleTransition { + private static Logger log = LoggerFactory.getLogger(CheckoutTransition.class.getName()); + private ArtifactsBusinessLogic artifactsManager; + + public UndoCheckoutTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation) { + super(componentUtils, lifecycleOperation); + + // authorized roles + Role[] resourceServiceCheckoutRoles = { Role.ADMIN, Role.DESIGNER }; + Role[] productCheckoutRoles = { Role.ADMIN, Role.PRODUCT_MANAGER }; + addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(resourceServiceCheckoutRoles)); + addAuthorizedRoles(ComponentTypeEnum.PRODUCT, Arrays.asList(productCheckoutRoles)); + + } + + @Override + public LifeCycleTransitionEnum getName() { + return LifeCycleTransitionEnum.UNDO_CHECKOUT; + } + + @Override + public AuditingActionEnum getAuditingAction() { + return AuditingActionEnum.UNDO_CHECKOUT_RESOURCE; + } + + public ArtifactsBusinessLogic getArtifactsBusinessLogic() { + return artifactsManager; + } + + public void setArtifactsBusinessLogic(ArtifactsBusinessLogic artifactsBusinessLogic) { + this.artifactsManager = artifactsBusinessLogic; + } + + @Override + public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) { + String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(); + log.debug("validate before undo checkout. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId()); + + // validate user + Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo); + if (userValidationResponse.isRight()) { + return userValidationResponse; + } + + // check resource is not locked by another user + if (!oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_ALREADY_CHECKED_IN, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + if (!modifier.equals(owner) && !modifier.getRole().equals(Role.ADMIN.name())) { + ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_CHECKOUT_BY_ANOTHER_USER, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId()); + return Either.right(error); + } + + return Either.left(true); + } + + @Override + public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) { + + Either<? extends Component, ResponseFormat> result = null; + log.debug("start performing undo-checkout for resource {}", component.getUniqueId()); + + Either<List<ArtifactDefinition>, StorageOperationStatus> artifactsRes = lifeCycleOperation.getComponentOperation(componentType.getNodeType()).getComponentArtifactsForDelete(component.getUniqueId(), componentType.getNodeType(), true); + if (artifactsRes.isRight()) { + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(artifactsRes.right().value()); + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + result = Either.right(responseFormat); + return result; + } + // TODO - start transaction + try { + NodeTypeEnum nodeType = componentType.getNodeType(); + + // 1. perform undo checkout on graph (update status and delete + // current version) + Either<? extends Component, StorageOperationStatus> undoCheckoutResourceResult = lifeCycleOperation.undoCheckout(nodeType, component, modifier, owner, true); + + if (undoCheckoutResourceResult.isRight()) { + log.debug("checkout failed on graph"); + StorageOperationStatus response = undoCheckoutResourceResult.right().value(); + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(response); + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + result = Either.right(responseFormat); + return result; + } + + // 2. delete unrelated artifacts + // use artifacts API to delete artifacts from swift / elasticsearch + + if (artifactsRes.left().value() != null) { + List<ArtifactDefinition> artifacts = artifactsRes.left().value(); + StorageOperationStatus deleteAllResourceArtifacts = artifactsManager.deleteAllComponentArtifactsIfNotOnGraph(artifacts); + + if (!deleteAllResourceArtifacts.equals(StorageOperationStatus.OK)) { + ActionStatus actionStatus = componentUtils.convertFromStorageResponse(deleteAllResourceArtifacts); + ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); + result = Either.right(responseFormat); + return result; + } + } + + result = Either.left(undoCheckoutResourceResult.left().value()); + } finally { + if (result == null || result.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDaoSystemError, "Change LifecycleState - Undo Checkout failed on graph"); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Change LifecycleState - Undo Checkout failed on graph"); + + log.debug("operation failed. do rollback"); + lifeCycleOperation.getResourceOperation().getTitanGenericDao().rollback(); + } else { + log.debug("operation success. do commit"); + lifeCycleOperation.getResourceOperation().getTitanGenericDao().commit(); + } + } + + return result; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/api/CategoryTypeEnum.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/api/CategoryTypeEnum.java new file mode 100644 index 0000000000..edfe56ebfa --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/api/CategoryTypeEnum.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.datamodel.api; + +import java.io.Serializable; + +public enum CategoryTypeEnum implements Serializable { + + CATEGORY("category"), SUBCATEGORY("sub-category"), GROUPING("grouping"); + + private String value; + + CategoryTypeEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/api/HighestFilterEnum.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/api/HighestFilterEnum.java new file mode 100644 index 0000000000..42ff4c900a --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/api/HighestFilterEnum.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.datamodel.api; + +public enum HighestFilterEnum { + + ALL, HIGHEST_ONLY, NON_HIGHEST_ONLY; + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/ArtifactUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/ArtifactUtils.java new file mode 100644 index 0000000000..9f66911461 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/ArtifactUtils.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.datamodel.utils; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; + +public class ArtifactUtils { + public static ArtifactDefinition findMasterArtifact(Map<String, ArtifactDefinition> deplymentArtifact, List<ArtifactDefinition> artifacts, List<String> artifactsList) { + for (String artifactUid : artifactsList) { + for (Entry<String, ArtifactDefinition> entry : deplymentArtifact.entrySet()) { + ArtifactDefinition artifact = entry.getValue(); + if (artifactUid.equalsIgnoreCase(artifact.getUniqueId())) { + artifacts.add(artifact); + } + + } + } + if (artifacts.size() == 1) { + return artifacts.get(0); + } + ArtifactDefinition masterArtifact = null; + for (ArtifactDefinition artifactInfo : artifacts) { + String atrifactType = artifactInfo.getArtifactType(); + if (atrifactType.equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType()) || atrifactType.equalsIgnoreCase(ArtifactTypeEnum.HEAT_NET.getType())) { + masterArtifact = artifactInfo; + continue; + } + if (atrifactType.equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + masterArtifact = artifactInfo; + break; + } + } + return masterArtifact; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/NodeTypeConvertUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/NodeTypeConvertUtils.java new file mode 100644 index 0000000000..ab71508e62 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/NodeTypeConvertUtils.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.datamodel.utils; + +import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; + +public class NodeTypeConvertUtils { + public static NodeTypeEnum getCategoryNodeTypeByComponentParam(ComponentTypeEnum componentTypeEnum, CategoryTypeEnum categoryType) { + NodeTypeEnum res = null; + if (componentTypeEnum != null) { + switch (componentTypeEnum) { + case SERVICE: + switch (categoryType) { + case CATEGORY: + res = NodeTypeEnum.ServiceNewCategory; + break; + + default: + // doesn't support subcategories or grouping + break; + } + break; + case RESOURCE: + switch (categoryType) { + case CATEGORY: + res = NodeTypeEnum.ResourceNewCategory; + break; + case SUBCATEGORY: + res = NodeTypeEnum.ResourceSubcategory; + break; + default: + // doesn't support grouping + break; + } + break; + case PRODUCT: + switch (categoryType) { + case CATEGORY: + res = NodeTypeEnum.ProductCategory; + break; + case SUBCATEGORY: + res = NodeTypeEnum.ProductSubcategory; + break; + case GROUPING: + res = NodeTypeEnum.ProductGrouping; + break; + } + break; + default: + break; + } + } + return res; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/AuditHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/AuditHandler.java new file mode 100644 index 0000000000..0cc415c80d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/AuditHandler.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution; + +import org.openecomp.sdc.be.components.distribution.engine.CambriaErrorResponse; +import org.openecomp.sdc.be.components.distribution.engine.SubscriberTypeEnum; +import org.openecomp.sdc.be.distribution.api.client.RegistrationRequest; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; + +public class AuditHandler { + ComponentsUtils componentsUtils; + String instanceID; + private RegistrationRequest registrationRequest; + + public AuditHandler(ComponentsUtils componentsUtils, String instanceID, RegistrationRequest registrationRequest) { + super(); + this.componentsUtils = componentsUtils; + this.instanceID = instanceID; + this.registrationRequest = registrationRequest; + } + + public void auditRegisterACL(CambriaErrorResponse registerResponse, SubscriberTypeEnum subscriberRole) { + + String topicName = (subscriberRole == SubscriberTypeEnum.CONSUMER) ? DistributionBusinessLogic.getNotificationTopicName(registrationRequest.getDistrEnvName()) + : DistributionBusinessLogic.getStatusTopicName(registrationRequest.getDistrEnvName()); + componentsUtils.auditTopicACLKeys(AuditingActionEnum.ADD_KEY_TO_TOPIC_ACL, registrationRequest.getDistrEnvName(), topicName, subscriberRole.name(), registrationRequest.getApiPublicKey(), String.valueOf(registerResponse.getHttpCode())); + } + + public void auditUnRegisterACL(CambriaErrorResponse registerResponse, SubscriberTypeEnum subscriberRole) { + String topicName = (subscriberRole == SubscriberTypeEnum.CONSUMER) ? DistributionBusinessLogic.getNotificationTopicName(registrationRequest.getDistrEnvName()) + : DistributionBusinessLogic.getStatusTopicName(registrationRequest.getDistrEnvName()); + componentsUtils.auditTopicACLKeys(AuditingActionEnum.REMOVE_KEY_FROM_TOPIC_ACL, registrationRequest.getDistrEnvName(), topicName, subscriberRole.name(), registrationRequest.getApiPublicKey(), String.valueOf(registerResponse.getHttpCode())); + + } + + public void auditRegisterRequest(CambriaErrorResponse registerResponse) { + componentsUtils.auditRegisterOrUnRegisterEvent(AuditingActionEnum.DISTRIBUTION_REGISTER, instanceID, registrationRequest.getApiPublicKey(), registrationRequest.getDistrEnvName(), String.valueOf(registerResponse.getHttpCode()), + registerResponse.getOperationStatus().name(), DistributionBusinessLogic.getNotificationTopicName(registrationRequest.getDistrEnvName()), DistributionBusinessLogic.getStatusTopicName(registrationRequest.getDistrEnvName())); + + } + + public void auditUnRegisterRequest(CambriaErrorResponse registerResponse) { + componentsUtils.auditRegisterOrUnRegisterEvent(AuditingActionEnum.DISTRIBUTION_UN_REGISTER, instanceID, registrationRequest.getApiPublicKey(), registrationRequest.getDistrEnvName(), String.valueOf(registerResponse.getHttpCode()), + registerResponse.getOperationStatus().name(), DistributionBusinessLogic.getNotificationTopicName(registrationRequest.getDistrEnvName()), DistributionBusinessLogic.getStatusTopicName(registrationRequest.getDistrEnvName())); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/DistributionBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/DistributionBusinessLogic.java new file mode 100644 index 0000000000..ae1de21ea8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/DistributionBusinessLogic.java @@ -0,0 +1,243 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution; + +import java.util.List; + +import javax.annotation.Resource; +import javax.ws.rs.core.Response; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.be.components.distribution.engine.CambriaErrorResponse; +import org.openecomp.sdc.be.components.distribution.engine.CambriaHandler; +import org.openecomp.sdc.be.components.distribution.engine.DistributionEngine; +import org.openecomp.sdc.be.components.distribution.engine.DistributionEngineInitTask; +import org.openecomp.sdc.be.components.distribution.engine.SubscriberTypeEnum; +import org.openecomp.sdc.be.components.impl.ResponseFormatManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.DistributionEngineConfiguration; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.distribution.api.client.CambriaOperationStatus; +import org.openecomp.sdc.be.distribution.api.client.RegistrationRequest; +import org.openecomp.sdc.be.distribution.api.client.ServerListResponse; +import org.openecomp.sdc.be.distribution.api.client.TopicRegistrationResponse; +import org.openecomp.sdc.be.distribution.api.client.TopicUnregistrationResponse; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import fj.data.Either; + +@Component("distributionBusinessLogic") +public class DistributionBusinessLogic { + public static final String REGISTER_IN_DISTRIBUTION_ENGINE = "registerInDistributionEngine"; + public static final String UN_REGISTER_IN_DISTRIBUTION_ENGINE = "unregisterInDistributionEngine"; + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private static Logger log = LoggerFactory.getLogger(DistributionBusinessLogic.class.getName()); + @Resource + private DistributionEngine distributionEngine; + + private ResponseFormatManager responseFormatManager = ResponseFormatManager.getInstance(); + private CambriaHandler cambriaHandler; + + public Either<ServerListResponse, ResponseFormat> getUebServerList() { + + DistributionEngineConfiguration distributionEngineConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + + List<String> serverList = distributionEngineConfiguration.getUebServers(); + + if (serverList != null && !serverList.isEmpty()) { + + ServerListResponse serverListResponse = new ServerListResponse(); + + serverListResponse.setUebServerList(serverList); + + return Either.left(serverListResponse); + } else { + ResponseFormat errorResponseWrapper = getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR); + return Either.right(errorResponseWrapper); + } + + } + + public void handleRegistration(Wrapper<Response> responseWrapper, RegistrationRequest registrationRequest, AuditHandler auditHandler) { + CambriaErrorResponse registerResponse = null; + try { + registerResponse = registerDistributionClientToTopic(responseWrapper, registrationRequest, SubscriberTypeEnum.PRODUCER); + auditHandler.auditRegisterACL(registerResponse, SubscriberTypeEnum.PRODUCER); + + if (responseWrapper.isEmpty()) { + registerResponse = registerDistributionClientToTopic(responseWrapper, registrationRequest, SubscriberTypeEnum.CONSUMER); + auditHandler.auditRegisterACL(registerResponse, SubscriberTypeEnum.CONSUMER); + // Second Register failed - unregister the first + if (!responseWrapper.isEmpty()) { + CambriaErrorResponse unRegisterResponse = unRegisterDistributionClientFromTopic(registrationRequest, SubscriberTypeEnum.PRODUCER); + auditHandler.auditUnRegisterACL(unRegisterResponse, SubscriberTypeEnum.PRODUCER); + } + } + + if (responseWrapper.isEmpty()) { + TopicRegistrationResponse okTopicResponse = buildTopicResponse(registrationRequest); + responseWrapper.setInnerElement(Response.status(HttpStatus.SC_OK).entity(okTopicResponse).build()); + } + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, REGISTER_IN_DISTRIBUTION_ENGINE, "registration of subscriber to topic"); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(REGISTER_IN_DISTRIBUTION_ENGINE, "registration of subscriber to topic"); + Response errorResponse = buildErrorResponse(getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR)); + responseWrapper.setInnerElement(errorResponse); + } finally { + auditHandler.auditRegisterRequest(registerResponse); + } + } + + public void handleUnRegistration(Wrapper<Response> responseWrapper, RegistrationRequest unRegistrationRequest, AuditHandler auditHandler) { + Wrapper<CambriaErrorResponse> cambriaResponseWrapper = new Wrapper<>(); + try { + CambriaErrorResponse unregisterClientProducerTopicResponse = unRegisterDistributionClientFromTopic(unRegistrationRequest, SubscriberTypeEnum.PRODUCER); + auditHandler.auditUnRegisterACL(unregisterClientProducerTopicResponse, SubscriberTypeEnum.PRODUCER); + updateResponseWrapper(cambriaResponseWrapper, unregisterClientProducerTopicResponse); + + CambriaErrorResponse unregisterClientConsumerTopicResponse = unRegisterDistributionClientFromTopic(unRegistrationRequest, SubscriberTypeEnum.CONSUMER); + auditHandler.auditUnRegisterACL(unregisterClientConsumerTopicResponse, SubscriberTypeEnum.CONSUMER); + updateResponseWrapper(cambriaResponseWrapper, unregisterClientConsumerTopicResponse); + + // Success unregister both topics + TopicUnregistrationResponse unregisterResponse = new TopicUnregistrationResponse(getNotificationTopicName(unRegistrationRequest.getDistrEnvName()), getStatusTopicName(unRegistrationRequest.getDistrEnvName()), + unregisterClientConsumerTopicResponse.getOperationStatus(), unregisterClientProducerTopicResponse.getOperationStatus()); + + if (cambriaResponseWrapper.getInnerElement().getOperationStatus() == CambriaOperationStatus.OK) { + responseWrapper.setInnerElement(Response.status(HttpStatus.SC_OK).entity(unregisterResponse).build()); + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, UN_REGISTER_IN_DISTRIBUTION_ENGINE, "unregistration failed"); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(UN_REGISTER_IN_DISTRIBUTION_ENGINE, "unregistration failed"); + responseWrapper.setInnerElement(Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(unregisterResponse).build()); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, UN_REGISTER_IN_DISTRIBUTION_ENGINE, "unregistration of subscriber to topic"); + Response errorResponse = buildErrorResponse(getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR)); + responseWrapper.setInnerElement(errorResponse); + + } finally { + auditHandler.auditUnRegisterRequest(cambriaResponseWrapper.getInnerElement()); + } + } + + private void updateResponseWrapper(Wrapper<CambriaErrorResponse> cambriaResponseWrapper, CambriaErrorResponse currentResponse) { + if (cambriaResponseWrapper.isEmpty()) { + cambriaResponseWrapper.setInnerElement(currentResponse); + } else if (currentResponse.getOperationStatus() != CambriaOperationStatus.OK) { + cambriaResponseWrapper.setInnerElement(currentResponse); + + } + + } + + public static String getNotificationTopicName(String envName) { + DistributionEngineConfiguration config = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + return DistributionEngineInitTask.buildTopicName(config.getDistributionNotifTopicName(), envName); + + } + + public static String getStatusTopicName(String envName) { + DistributionEngineConfiguration config = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + return DistributionEngineInitTask.buildTopicName(config.getDistributionStatusTopicName(), envName); + + } + + protected CambriaErrorResponse unRegisterDistributionClientFromTopic(RegistrationRequest unRegistrationRequest, SubscriberTypeEnum subscriberType) { + DistributionEngineConfiguration config = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + String topicName; + if (subscriberType == SubscriberTypeEnum.PRODUCER) { + topicName = getStatusTopicName(unRegistrationRequest.getDistrEnvName()); + } else { + topicName = getNotificationTopicName(unRegistrationRequest.getDistrEnvName()); + + } + log.debug("unregistering client as {} , from topic: {}", subscriberType.name(), topicName); + return getCambriaHandler().unRegisterFromTopic(config.getUebServers(), topicName, config.getUebPublicKey(), config.getUebSecretKey(), unRegistrationRequest.getApiPublicKey(), subscriberType); + } + + private TopicRegistrationResponse buildTopicResponse(RegistrationRequest registrationRequest) { + DistributionEngineConfiguration config = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + String statusTopicName = DistributionEngineInitTask.buildTopicName(config.getDistributionStatusTopicName(), registrationRequest.getDistrEnvName()); + String notificationTopicName = DistributionEngineInitTask.buildTopicName(config.getDistributionNotifTopicName(), registrationRequest.getDistrEnvName()); + + TopicRegistrationResponse topicResponse = new TopicRegistrationResponse(); + topicResponse.setDistrNotificationTopicName(notificationTopicName); + topicResponse.setDistrStatusTopicName(statusTopicName); + return topicResponse; + } + + protected CambriaErrorResponse registerDistributionClientToTopic(Wrapper<Response> responseWrapper, RegistrationRequest registrationRequest, SubscriberTypeEnum subscriberType) { + DistributionEngineConfiguration config = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration(); + String topicName, errorMsg; + + // Register for notifications as consumer + if (subscriberType == SubscriberTypeEnum.CONSUMER) { + topicName = DistributionEngineInitTask.buildTopicName(config.getDistributionNotifTopicName(), registrationRequest.getDistrEnvName()); + errorMsg = "registration of subscriber to topic:" + topicName + " as consumer failed"; + } + // Register for status as producer + else { + topicName = DistributionEngineInitTask.buildTopicName(config.getDistributionStatusTopicName(), registrationRequest.getDistrEnvName()); + errorMsg = "registration of subscriber to topic:" + topicName + " as producer failed"; + } + log.debug("registering client as {} , from topic: {}", subscriberType.name(), topicName); + CambriaErrorResponse registerToTopic = getCambriaHandler().registerToTopic(config.getUebServers(), topicName, config.getUebPublicKey(), config.getUebSecretKey(), registrationRequest.getApiPublicKey(), subscriberType); + + if (registerToTopic.getOperationStatus() != CambriaOperationStatus.OK) { + Response failedRegistrationResponse = buildErrorResponse(getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR)); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, REGISTER_IN_DISTRIBUTION_ENGINE, errorMsg); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(REGISTER_IN_DISTRIBUTION_ENGINE, errorMsg); + responseWrapper.setInnerElement(failedRegistrationResponse); + } + return registerToTopic; + } + + protected Response buildErrorResponse(ResponseFormat requestErrorWrapper) { + Response response = Response.status(requestErrorWrapper.getStatus()).entity(gson.toJson(requestErrorWrapper.getRequestError())).build(); + return response; + } + + public ResponseFormatManager getResponseFormatManager() { + return responseFormatManager; + } + + public DistributionEngine getDistributionEngine() { + return distributionEngine; + } + + public CambriaHandler getCambriaHandler() { + if (cambriaHandler == null) { + cambriaHandler = new CambriaHandler(); + } + return cambriaHandler; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/CambriaOperationStatus.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/CambriaOperationStatus.java new file mode 100644 index 0000000000..a6a6602cb0 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/CambriaOperationStatus.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.api.client; + +public enum CambriaOperationStatus { + OK, CONNNECTION_ERROR, NOT_FOUND, TOPIC_ALREADY_EXIST, OBJECT_NOT_FOUND, INTERNAL_SERVER_ERROR, AUTHENTICATION_ERROR, UNKNOWN_HOST_ERROR, +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/RegistrationRequest.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/RegistrationRequest.java new file mode 100644 index 0000000000..ef14efe4f8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/RegistrationRequest.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.api.client; + +public class RegistrationRequest { + String apiPublicKey; + String distrEnvName; + + public RegistrationRequest(String apiPublicKey, String distrEnvName) { + this.apiPublicKey = apiPublicKey; + this.distrEnvName = distrEnvName; + } + + public String getApiPublicKey() { + return apiPublicKey; + } + + public String getDistrEnvName() { + return distrEnvName; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/ServerListResponse.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/ServerListResponse.java new file mode 100644 index 0000000000..267a691e29 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/ServerListResponse.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.api.client; + +import java.util.List; + +public class ServerListResponse { + + private List<String> uebServerList; + + public List<String> getUebServerList() { + return uebServerList; + } + + public void setUebServerList(List<String> uebServerList) { + this.uebServerList = uebServerList; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/TopicRegistrationResponse.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/TopicRegistrationResponse.java new file mode 100644 index 0000000000..e2a34a19d5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/TopicRegistrationResponse.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.api.client; + +public class TopicRegistrationResponse { + String distrNotificationTopicName; + String distrStatusTopicName; + + public void setDistrNotificationTopicName(String distrNotificationTopicName) { + this.distrNotificationTopicName = distrNotificationTopicName; + } + + public void setDistrStatusTopicName(String distrStatusTopicName) { + this.distrStatusTopicName = distrStatusTopicName; + } + + public String getDistrNotificationTopicName() { + return distrNotificationTopicName; + } + + public String getDistrStatusTopicName() { + return distrStatusTopicName; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/TopicUnregistrationResponse.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/TopicUnregistrationResponse.java new file mode 100644 index 0000000000..ffb9f9352f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/api/client/TopicUnregistrationResponse.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.api.client; + +public class TopicUnregistrationResponse { + String distrNotificationTopicName; + String distrStatusTopicName; + CambriaOperationStatus notificationUnregisterResult; + CambriaOperationStatus statusUnregisterResult; + + public TopicUnregistrationResponse(String distrNotificationTopicName, String distrStatusTopicName, CambriaOperationStatus notificationUnregisterResult, CambriaOperationStatus statusUnregisterResult) { + super(); + this.distrNotificationTopicName = distrNotificationTopicName; + this.distrStatusTopicName = distrStatusTopicName; + this.notificationUnregisterResult = notificationUnregisterResult; + this.statusUnregisterResult = statusUnregisterResult; + } + + public String getDistrNotificationTopicName() { + return distrNotificationTopicName; + } + + public String getDistrStatusTopicName() { + return distrStatusTopicName; + } + + public CambriaOperationStatus getNotificationUnregisterResult() { + return notificationUnregisterResult; + } + + public CambriaOperationStatus getStatusUnregisterResult() { + return statusUnregisterResult; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/servlet/DistributionCatalogServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/servlet/DistributionCatalogServlet.java new file mode 100644 index 0000000000..a5d1093648 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/servlet/DistributionCatalogServlet.java @@ -0,0 +1,230 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.servlet; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.servlets.BeGenericServlet; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Singleton +public class DistributionCatalogServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(DistributionCatalogServlet.class.getName()); + + // ******************************************************* + // Download (GET) artifacts + // **********************************************************/ + + @GET + @Path("/services/{serviceName}/{serviceVersion}/artifacts/{artifactName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download service artifact", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact downloaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Artifact not found") }) + public Response downloadServiceArtifact(@PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion, @PathParam("artifactName") final String artifactName, + @Context final HttpServletRequest request) { + Response response = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + AuditingActionEnum auditingActionEnum = AuditingActionEnum.DISTRIBUTION_ARTIFACT_DOWNLOAD; + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI); + + if (instanceIdHeader == null || instanceIdHeader.isEmpty()) { + log.debug("Missing X-ECOMP-InstanceID header"); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<byte[], ResponseFormat> downloadRsrcArtifactEither = artifactsLogic.downloadServiceArtifactByNames(serviceName, serviceVersion, artifactName); + if (downloadRsrcArtifactEither.isRight()) { + ResponseFormat responseFormat = downloadRsrcArtifactEither.right().value(); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + response = buildErrorResponse(responseFormat); + } else { + byte[] value = downloadRsrcArtifactEither.left().value(); + InputStream is = new ByteArrayInputStream(value); + + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName)); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + response = buildOkResponse(responseFormat, is, headers); + } + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "download Murano package artifact for service - external API"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download Murano package artifact for service - external API"); + log.debug("download artifact failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/services/{serviceName}/{serviceVersion}/resources/{resourceName}/{resourceVersion}/artifacts/{artifactName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download resource artifact", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact downloaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Artifact not found") }) + public Response downloadResourceArtifact(@PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion, @PathParam("resourceName") final String resourceName, + @PathParam("resourceVersion") final String resourceVersion, @PathParam("artifactName") final String artifactName, @Context final HttpServletRequest request) { + Response response = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + AuditingActionEnum auditingActionEnum = AuditingActionEnum.DISTRIBUTION_ARTIFACT_DOWNLOAD; + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI); + + if (instanceIdHeader == null || instanceIdHeader.isEmpty()) { + log.debug("Missing X-ECOMP-InstanceID header"); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<byte[], ResponseFormat> downloadRsrcArtifactEither = artifactsLogic.downloadRsrcArtifactByNames(serviceName, serviceVersion, resourceName, resourceVersion, artifactName); + if (downloadRsrcArtifactEither.isRight()) { + ResponseFormat responseFormat = downloadRsrcArtifactEither.right().value(); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + response = buildErrorResponse(responseFormat); + } else { + byte[] value = downloadRsrcArtifactEither.left().value(); + // Returning 64-encoded as it was received during upload + InputStream is = new ByteArrayInputStream(value); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName)); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + response = buildOkResponse(responseFormat, is, headers); + } + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "download interface artifact for resource - external API"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API"); + log.debug("download artifact failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + // -------------------------------- + + @GET + @Path("/services/{serviceName}/{serviceVersion}/resourceInstances/{resourceInstanceName}/artifacts/{artifactName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download resource artifact", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact downloaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Artifact not found") }) + public Response downloadResourceInstanceArtifact(@PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion, @PathParam("resourceInstanceName") final String resourceInstanceName, + @PathParam("artifactName") final String artifactName, @Context final HttpServletRequest request) { + Response response = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + AuditingActionEnum auditingActionEnum = AuditingActionEnum.DISTRIBUTION_ARTIFACT_DOWNLOAD; + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI); + + if (instanceIdHeader == null || instanceIdHeader.isEmpty()) { + log.debug("Missing X-ECOMP-InstanceID header"); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<byte[], ResponseFormat> downloadRsrcArtifactEither = artifactsLogic.downloadRsrcInstArtifactByNames(serviceName, serviceVersion, resourceInstanceName, artifactName); + if (downloadRsrcArtifactEither.isRight()) { + ResponseFormat responseFormat = downloadRsrcArtifactEither.right().value(); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + response = buildErrorResponse(responseFormat); + } else { + byte[] value = downloadRsrcArtifactEither.left().value(); + // Returning 64-encoded as it was received during upload + InputStream is = new ByteArrayInputStream(value); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName)); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditDistributionDownload(responseFormat, auditingActionEnum, additionalParam); + response = buildOkResponse(responseFormat, is, headers); + } + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "download interface artifact for resource - external API"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API"); + log.debug("download artifact failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + // -------------------------------- +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/servlet/DistributionServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/servlet/DistributionServlet.java new file mode 100644 index 0000000000..b1556bafc3 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/distribution/servlet/DistributionServlet.java @@ -0,0 +1,279 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.distribution.servlet; + +import javax.annotation.Resource; +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.distribution.AuditHandler; +import org.openecomp.sdc.be.distribution.DistributionBusinessLogic; +import org.openecomp.sdc.be.distribution.api.client.RegistrationRequest; +import org.openecomp.sdc.be.distribution.api.client.ServerListResponse; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.servlets.BeGenericServlet; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.util.HttpUtil; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1") +@Singleton +public class DistributionServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(DistributionServlet.class.getName()); + @Resource + private DistributionBusinessLogic distributionLogic; + + @GET + @Path("/distributionUebCluster") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getUebServerList(@Context final HttpServletRequest request, @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) String instanceId, @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, + @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, @HeaderParam(value = Constants.ACCEPT_HEADER) String accept) { + init(request); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + Response response = null; + ResponseFormat responseFormat = null; + if (instanceId == null) { + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + response = buildErrorResponse(responseFormat); + getComponentsUtils().auditMissingInstanceId(AuditingActionEnum.GET_UEB_CLUSTER, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage()); + return response; + } + try { + Either<ServerListResponse, ResponseFormat> actionResponse = distributionLogic.getUebServerList(); + + if (actionResponse.isRight()) { + responseFormat = actionResponse.right().value(); + response = buildErrorResponse(responseFormat); + } else { + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + response = buildOkResponse(responseFormat, actionResponse.left().value()); + } + + getComponentsUtils().auditGetUebCluster(AuditingActionEnum.GET_UEB_CLUSTER, instanceId, null, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "failed to get ueb serbver list from cofiguration"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("failed to get ueb serbver list from cofiguration"); + log.debug("failed to get ueb serbver list from cofiguration", e); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + getComponentsUtils().auditGetUebCluster(AuditingActionEnum.GET_UEB_CLUSTER, instanceId, null, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage()); + response = buildErrorResponse(responseFormat); + return response; + } + + } + + /** + * Returns list of valid artifact types for validation done in the distribution client.<br> + * The list is the representation of the values of the enum ArtifactTypeEnum. + * + * @param request + * @param instanceId + * @param requestId + * @param authorization + * @param accept + * @return + */ + @GET + @Path("/artifactTypes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getValidArtifactTypes(@Context final HttpServletRequest request, @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) String instanceId, @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, + @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, @HeaderParam(value = Constants.ACCEPT_HEADER) String accept) { + init(request); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + Response response = null; + + Wrapper<Response> responseWrapper = new Wrapper<>(); + + validateHeaders(responseWrapper, request, AuditingActionEnum.GET_VALID_ARTIFACT_TYPES); + if (responseWrapper.isEmpty()) { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), ArtifactTypeEnum.values()); + } else { + response = responseWrapper.getInnerElement(); + } + return response; + } + + @POST + @Path("/registerForDistribution") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response registerForDistribution(@Context final HttpServletRequest request, String requestJson) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + init(request); + + Wrapper<Response> responseWrapper = new Wrapper<>(); + Wrapper<RegistrationRequest> registrationRequestWrapper = new Wrapper<>(); + + validateHeaders(responseWrapper, request, AuditingActionEnum.ADD_KEY_TO_TOPIC_ACL); + + if (responseWrapper.isEmpty()) { + validateJson(responseWrapper, registrationRequestWrapper, requestJson); + } + if (responseWrapper.isEmpty()) { + validateEnv(responseWrapper, registrationRequestWrapper.getInnerElement().getDistrEnvName()); + } + + if (responseWrapper.isEmpty()) { + distributionLogic.handleRegistration(responseWrapper, registrationRequestWrapper.getInnerElement(), buildAuditHandler(request, registrationRequestWrapper.getInnerElement())); + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, DistributionBusinessLogic.REGISTER_IN_DISTRIBUTION_ENGINE, "registration validation failed"); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(DistributionBusinessLogic.REGISTER_IN_DISTRIBUTION_ENGINE, "registration validation failed"); + } + + return responseWrapper.getInnerElement(); + } + + @POST + @Path("/unRegisterForDistribution") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response unRegisterForDistribution(@Context final HttpServletRequest request, String requestJson) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + init(request); + + Wrapper<Response> responseWrapper = new Wrapper<>(); + Wrapper<RegistrationRequest> unRegistrationRequestWrapper = new Wrapper<>(); + + validateHeaders(responseWrapper, request, AuditingActionEnum.REMOVE_KEY_FROM_TOPIC_ACL); + + if (responseWrapper.isEmpty()) { + validateJson(responseWrapper, unRegistrationRequestWrapper, requestJson); + } + if (responseWrapper.isEmpty()) { + validateEnv(responseWrapper, unRegistrationRequestWrapper.getInnerElement().getDistrEnvName()); + } + if (responseWrapper.isEmpty()) { + distributionLogic.handleUnRegistration(responseWrapper, unRegistrationRequestWrapper.getInnerElement(), buildAuditHandler(request, unRegistrationRequestWrapper.getInnerElement())); + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeDistributionEngineSystemError, DistributionBusinessLogic.UN_REGISTER_IN_DISTRIBUTION_ENGINE, "unregistration validation failed"); + BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(DistributionBusinessLogic.UN_REGISTER_IN_DISTRIBUTION_ENGINE, "unregistration validation failed"); + } + + return responseWrapper.getInnerElement(); + } + + private void validateEnv(Wrapper<Response> responseWrapper, String distrEnvName) { + + // DE194021 + StorageOperationStatus environmentStatus = distributionLogic.getDistributionEngine().isEnvironmentAvailable(); + // DE194021 + // StorageOperationStatus environmentStatus = + // distributionLogic.getDistributionEngine().isEnvironmentAvailable(distrEnvName); + if (environmentStatus != StorageOperationStatus.OK) { + if (environmentStatus == StorageOperationStatus.DISTR_ENVIRONMENT_NOT_FOUND) { + Response missingHeaderResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.DISTRIBUTION_ENV_DOES_NOT_EXIST)); + responseWrapper.setInnerElement(missingHeaderResponse); + } else { + Response missingHeaderResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR)); + responseWrapper.setInnerElement(missingHeaderResponse); + } + } + + } + + private void init(HttpServletRequest request) { + if (distributionLogic == null) { + distributionLogic = getDistributionBL(request.getSession().getServletContext()); + } + } + + private void validateHeaders(Wrapper<Response> responseWrapper, HttpServletRequest request, AuditingActionEnum auditingAction) { + if (request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER) == null) { + Response missingHeaderResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID)); + responseWrapper.setInnerElement(missingHeaderResponse); + // Audit + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditMissingInstanceId(auditingAction, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage()); + + } + + } + + private void validateJson(Wrapper<Response> responseWrapper, Wrapper<RegistrationRequest> registrationRequestWrapper, String requestJson) { + if (requestJson == null || requestJson.isEmpty()) { + Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_BODY)); + responseWrapper.setInnerElement(missingBodyResponse); + } else { + Either<RegistrationRequest, Exception> eitherRegistration = HttpUtil.convertJsonStringToObject(requestJson, RegistrationRequest.class); + if (eitherRegistration.isLeft()) { + RegistrationRequest registrationRequest = eitherRegistration.left().value(); + if (registrationRequest.getApiPublicKey() == null) { + Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_PUBLIC_KEY)); + responseWrapper.setInnerElement(missingBodyResponse); + + } else if (registrationRequest.getDistrEnvName() == null) { + Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_ENV_NAME)); + responseWrapper.setInnerElement(missingBodyResponse); + } else { + registrationRequestWrapper.setInnerElement(registrationRequest); + } + } else { + Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_BODY)); + responseWrapper.setInnerElement(missingBodyResponse); + } + } + + } + + private DistributionBusinessLogic getDistributionBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + return webApplicationContext.getBean(DistributionBusinessLogic.class); + } + + private AuditHandler buildAuditHandler(HttpServletRequest request, RegistrationRequest registrationRequest) { + return new AuditHandler(getComponentsUtils(), request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER), registrationRequest); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java new file mode 100644 index 0000000000..5670239ef7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java @@ -0,0 +1,376 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.ecomp; + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.ecomp.converters.EcompRoleConverter; +import org.openecomp.sdc.be.ecomp.converters.EcompUserConverter; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.web.context.ContextLoader; + +import org.openecomp.portalsdk.core.onboarding.crossapi.IPortalRestAPIService; +import org.openecomp.portalsdk.core.onboarding.crossapi.PortalAPIException; +import org.openecomp.portalsdk.core.restful.domain.EcompRole; +import org.openecomp.portalsdk.core.restful.domain.EcompUser; + +import fj.data.Either; + +/* + * PortalAPIException(String message, Throwable cause); + */ +public class EcompIntImpl implements IPortalRestAPIService { + private static Logger log = LoggerFactory.getLogger(EcompIntImpl.class.getName()); + + public EcompIntImpl() { + log.debug("EcompIntImpl Class Instantiated"); + } + + @Override + public void pushUser(EcompUser user) throws PortalAPIException { + log.debug("Start handle request of ECOMP pushUser"); + try { + if (user == null) { + BeEcompErrorManager.getInstance().logInvalidInputError("PushUser", "Recieved null for argument user", ErrorSeverity.INFO); + log.debug("Recieved null for argument user"); + throw new PortalAPIException("Recieved null for argument user"); + } + + UserBusinessLogic userBusinessLogic = getUserBusinessLogic(); + + final String modifierAttId = "jh0003"; + User modifier = new User(); + modifier.setUserId(modifierAttId); + log.debug("modifier id is {}", modifierAttId); + + Either<User, String> newASDCUser = EcompUserConverter.convertEcompUserToUser(user); + if (newASDCUser.isRight()) { + BeEcompErrorManager.getInstance().logInvalidInputError("PushUser", "Failed to convert user", ErrorSeverity.INFO); + log.debug("Failed to create user {}",user.toString()); + throw new PortalAPIException("Failed to create user " + newASDCUser.right().value()); + } else if (newASDCUser.left().value() == null) { + BeEcompErrorManager.getInstance().logInvalidInputError("PushUser", "NULL pointer returned from user converter", ErrorSeverity.INFO); + log.debug("Failed to create user {}", user.toString()); + throw new PortalAPIException("Failed to create user " + newASDCUser.right().value()); + } + + User convertedAsdcUser = newASDCUser.left().value(); + Either<User, ResponseFormat> createUserResponse = userBusinessLogic.createUser(modifier, convertedAsdcUser); + + // ALREADY EXIST ResponseFormat + final String ALREADY_EXISTS_RESPONSE_ID = "SVC4006"; + + if (createUserResponse.isRight()) { + if (!createUserResponse.right().value().getMessageId().equals(ALREADY_EXISTS_RESPONSE_ID)) { + log.debug("Failed to create user {}", user.toString()); + BeEcompErrorManager.getInstance().logInvalidInputError("PushUser", "Failed to create user", ErrorSeverity.ERROR); + throw new PortalAPIException("Failed to create user" + createUserResponse.right()); + } + log.debug("User already exist {}", user.toString()); + } + log.debug("User created {}", user.toString()); + } catch (Exception e) { + log.debug("Failed to create user {}", user, e); + BeEcompErrorManager.getInstance().logInvalidInputError("PushUser", "Failed to create user", ErrorSeverity.ERROR); + throw new PortalAPIException("Failed to create user", e); + } + } + + /* + * (non-Javadoc) + * + * + * loginId - equals to userId + * + */ + @Override + public void editUser(String loginId, EcompUser user) throws PortalAPIException { + log.debug("Start handle request of ECOMP editUser"); + + try { + if (user == null) { + log.debug("Recieved null for argument user"); + BeEcompErrorManager.getInstance().logInvalidInputError("EditUser", "Recieved null for argument user", ErrorSeverity.INFO); + throw new PortalAPIException("Recieved null for argument user"); + } else if (loginId == null) { + log.debug("Recieved null for argument loginId"); + BeEcompErrorManager.getInstance().logInvalidInputError("EditUser", "Recieved null for argument loginId", ErrorSeverity.INFO); + throw new PortalAPIException("Recieved null for argument loginId"); + } + + UserBusinessLogic userBusinessLogic = getUserBusinessLogic(); + + if (user.getLoginId() != null && !user.getLoginId().equals(loginId)) { + log.debug("loginId and user loginId not equal"); + BeEcompErrorManager.getInstance().logInvalidInputError("EditUser", "loginId and user loginId not equal", ErrorSeverity.INFO); + throw new PortalAPIException("loginId not equals to the user loginId field"); + } else if (user.getLoginId() == null) { + user.setLoginId(loginId); + } + + Either<User, String> asdcUser = EcompUserConverter.convertEcompUserToUser(user); + if (asdcUser.isRight()) { + log.debug("Failed to convert user"); + BeEcompErrorManager.getInstance().logInvalidInputError("EditUser", "Failed to convert user", ErrorSeverity.INFO); + throw new PortalAPIException(asdcUser.right().value()); + } else if (asdcUser.left().value() == null) { + log.debug("NULL pointer returned from user converter"); + BeEcompErrorManager.getInstance().logInvalidInputError("EditUser", "NULL pointer returned from user converter", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to edit user"); + } + + Either<User, ResponseFormat> updateUserCredentialsResponse = userBusinessLogic.updateUserCredentials(asdcUser.left().value()); + + if (updateUserCredentialsResponse.isRight()) { + log.debug("Failed to updateUserCredentials"); + BeEcompErrorManager.getInstance().logInvalidInputError("EditUser", "Failed to updateUserCredentials", ErrorSeverity.ERROR); + throw new PortalAPIException("Failed to edit user" + updateUserCredentialsResponse.right().value()); + } + } catch (Exception e) { + log.debug("Failed to updateUserCredentials"); + throw new PortalAPIException("Failed to edit user", e); + } + + } + + @Override + public EcompUser getUser(String loginId) throws PortalAPIException { + log.debug("Start handle request of ECOMP getUser"); + + try { + + if (loginId == null) { + log.debug("Recieved null for argument loginId"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUser", "Recieved null for argument loginId", ErrorSeverity.INFO); + throw new PortalAPIException("Recieved null for argument loginId"); + } + + UserBusinessLogic userBusinessLogic = getUserBusinessLogic(); + + Either<User, ActionStatus> getUserResponse = userBusinessLogic.getUser(loginId, false); + + if (getUserResponse.isRight()) { + log.debug("Failed to get User"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUser", "Failed to get User", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get User" + getUserResponse.right()); + } else { + if (getUserResponse.left().value() != null) { + Either<EcompUser, String> ecompUser = EcompUserConverter.convertUserToEcompUser(getUserResponse.left().value()); + if (ecompUser.isLeft() && ecompUser.left().value() != null) { + return ecompUser.left().value(); + } else { + log.debug("Failed to get User"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUser", "Failed to get User", ErrorSeverity.INFO); + throw new PortalAPIException(ecompUser.right().value()); + } + } else { + log.debug("Failed to get User"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUser", "Failed to get User", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get User" + getUserResponse.right()); + } + } + } catch (Exception e) { + log.debug("Failed to get User"); + throw new PortalAPIException("Failed to get User", e); + } + } + + @Override + public List<EcompUser> getUsers() throws PortalAPIException { + log.debug("Start handle request of ECOMP getUsers"); + + try { + UserBusinessLogic userBusinessLogic = getUserBusinessLogic(); + + final String modifierAttId = "jh0003"; + + Either<List<User>, ResponseFormat> getUsersResponse = userBusinessLogic.getUsersList(modifierAttId, null, null); + + if (getUsersResponse.isRight()) { + log.debug("Failed to get Users"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUsers", "Failed to get users", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get Users" + getUsersResponse.right()); + } else { + if (getUsersResponse.left().value() != null) { + List<EcompUser> ecompUserList = new LinkedList<>(); + for (User user : getUsersResponse.left().value()) { + Either<EcompUser, String> ecompUser = EcompUserConverter.convertUserToEcompUser(user); + if (ecompUser.isRight()) { + log.debug("Failed to convert User {}", user); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUsers", "Failed to convert User" + user.toString(), ErrorSeverity.WARNING); + continue; + } else if (ecompUser.left().value() == null) { + log.debug("Failed to convert User {}", user); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUsers", "Failed to convert User" + user.toString(), ErrorSeverity.WARNING); + continue; + } + ecompUserList.add(ecompUser.left().value()); + } + return ecompUserList; + } else { + log.debug("Failed to get users"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUsers", "Failed to get users", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get Users" + getUsersResponse.right()); + } + } + } catch (Exception e) { + log.debug("Failed to get users"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUsers", "Failed to get users", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get Users", e); + } + } + + @Override + public List<EcompRole> getAvailableRoles() throws PortalAPIException { + log.debug("Start handle request of ECOMP getAvailableRoles"); + try { + List<EcompRole> ecompRolesList = new LinkedList<>(); + for (Role role : Role.values()) { + EcompRole ecompRole = new EcompRole(); + ecompRole.setId(new Long(role.ordinal())); + ecompRole.setName(role.name()); + ecompRolesList.add(ecompRole); + } + + if (ecompRolesList.isEmpty()) { + throw new PortalAPIException(); + } + + return ecompRolesList; + } catch (Exception e) { + log.debug("Failed to fetch roles"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetAvailableRoles", "Failed to fetch roles", ErrorSeverity.INFO); + throw new PortalAPIException("Roles fetching failed", e); + } + + } + + /** + * The user role updated through this method only + */ + @Override + public void pushUserRole(String loginId, List<EcompRole> roles) throws PortalAPIException { + log.debug("Start handle request of ECOMP pushUserRole"); + + final String modifierAttId = "jh0003"; + User modifier = new User(); + modifier.setUserId(modifierAttId); + log.debug("modifier id is {}", modifierAttId); + + UserBusinessLogic userBusinessLogic = getUserBusinessLogic(); + + String updatedRole = null; + + if (roles == null) { + throw new PortalAPIException("Error: Recieved null for roles"); + } else if (roles.iterator().hasNext()) { + EcompRole ecompRole = roles.iterator().next(); + updatedRole = EcompRoleConverter.convertEcompRoleToRole(ecompRole); + log.debug("pushing role: {} to user: {}", updatedRole, loginId); + } else { + log.debug("Error: No roles in List"); + BeEcompErrorManager.getInstance().logInvalidInputError("PushUserRole", "Failed to fetch roles", ErrorSeverity.INFO); + throw new PortalAPIException("Error: No roles in List"); + } + + Either<User, ResponseFormat> updateUserRoleResponse = userBusinessLogic.updateUserRole(modifier, loginId, updatedRole); + if (updateUserRoleResponse.isRight()) { + log.debug("Error: Failed to update role"); + BeEcompErrorManager.getInstance().logInvalidInputError("PushUserRole", "Failed to update role", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to update role" + updateUserRoleResponse.right().value().toString()); + } + } + + @Override + public List<EcompRole> getUserRoles(String loginId) throws PortalAPIException { + try { + log.debug("Start handle request of ECOMP getUserRoles"); + + UserBusinessLogic userBusinessLogic = getUserBusinessLogic(); + + Either<User, ActionStatus> getUserResponse = userBusinessLogic.getUser(loginId, false); + + if (getUserResponse.isRight()) { + log.debug("Error: Failed to get Roles"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUserRoles", "Failed to get Roles", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get Roles" + getUserResponse.right()); + } else { + if (getUserResponse.left().value() != null) { + Either<EcompUser, String> ecompUser = EcompUserConverter.convertUserToEcompUser(getUserResponse.left().value()); + if (ecompUser.isRight()) { + log.debug("Error: Failed to convert Roles"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUserRoles", "Failed to convert Roles", ErrorSeverity.ERROR); + throw new PortalAPIException(ecompUser.right().value()); + } else if (ecompUser.left().value() == null) { + log.debug("Error: Failed to convert Roles"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUserRoles", "Failed to convert Roles", ErrorSeverity.ERROR); + throw new PortalAPIException(); + } + + return new LinkedList<>(ecompUser.left().value().getRoles()); + } else { + log.debug("Error: Failed to get Roles"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUserRoles", "Failed to get Roles", ErrorSeverity.ERROR); + throw new PortalAPIException("Failed to get Roles" + getUserResponse.right()); + } + } + } catch (Exception e) { + log.debug("Error: Failed to get Roles"); + BeEcompErrorManager.getInstance().logInvalidInputError("GetUserRoles", "Failed to get Roles", ErrorSeverity.INFO); + throw new PortalAPIException("Failed to get Roles", e); + } + } + + @Override + public boolean isAppAuthenticated(HttpServletRequest request) throws PortalAPIException { + // TODO Validation should be changed completely + final String USERNAME = request.getHeader("username"); + final String PASSWORD = request.getHeader("password"); + + if (USERNAME != null && PASSWORD != null) { + if (!USERNAME.equals("") && !PASSWORD.equals("")) { + log.debug("User authenticated - Username: {} Password: {}", USERNAME, PASSWORD); + return true; + } + } + + log.debug("User authentication failed"); + return false; + } + + private UserBusinessLogic getUserBusinessLogic() { + ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext(); + UserBusinessLogic userBusinessLogic = (UserBusinessLogic) ctx.getBean("userBusinessLogic"); + return userBusinessLogic; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/EcompRoleConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/EcompRoleConverter.java new file mode 100644 index 0000000000..ca970ce45f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/EcompRoleConverter.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.ecomp.converters; + +import org.openecomp.sdc.be.user.Role; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.openecomp.portalsdk.core.restful.domain.EcompRole; + +public final class EcompRoleConverter { + + private static Logger log = LoggerFactory.getLogger(EcompRoleConverter.class.getName()); + + private EcompRoleConverter() { + } + + // TODO Add Either or Exception in case of convertation failure + public static String convertEcompRoleToRole(EcompRole ecompRole) { + + log.debug("converting role"); + if (ecompRole == null) { + log.debug("recieved null for roles"); + return null; + } + + for (Role role : Role.values()) { + if (role.ordinal() == ecompRole.getId()) { + return role.name(); + } + } + log.debug("no roles converted"); + return null; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/EcompUserConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/EcompUserConverter.java new file mode 100644 index 0000000000..e83b53c2a4 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/EcompUserConverter.java @@ -0,0 +1,118 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.ecomp.converters; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.openecomp.sdc.be.dao.utils.UserStatusEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.user.Role; + +import org.openecomp.portalsdk.core.restful.domain.EcompRole; +import org.openecomp.portalsdk.core.restful.domain.EcompUser; + +import fj.data.Either; + +public final class EcompUserConverter { + + private EcompUserConverter() { + } + + // private static final EcompUserConverter instance = new + // EcompUserConverter(); + + /* + * public static EcompUserConverter getInsatnce() { return instance; } + */ + + public static Either<EcompUser, String> convertUserToEcompUser(User asdcUser) { + EcompUser convertedUser = new EcompUser(); + + if (asdcUser == null) { + return Either.right("User is null"); + } + + convertedUser.setFirstName(asdcUser.getFirstName()); + convertedUser.setLastName(asdcUser.getLastName()); + convertedUser.setLoginId(asdcUser.getUserId()); + convertedUser.setOrgUserId(asdcUser.getUserId()); + convertedUser.setEmail(asdcUser.getEmail()); + + if (asdcUser.getStatus().equals(UserStatusEnum.ACTIVE)) { + convertedUser.setActive(true); + } else if (asdcUser.getStatus().equals(UserStatusEnum.INACTIVE)) { + convertedUser.setActive(false); + } + + EcompRole convertedRole = new EcompRole(); + for (Role role : Role.values()) { + if (role.name().equals(asdcUser.getRole()) || role.toString().equals(asdcUser.getRole())) { + convertedRole.setName(role.name()); + convertedRole.setId(new Long(role.ordinal())); + break; + } + } + + Set<EcompRole> convertedRoleSet = new HashSet<>(); + convertedRoleSet.add(convertedRole); + convertedUser.setRoles(convertedRoleSet); + + return Either.left(convertedUser); + } + + public static Either<User, String> convertEcompUserToUser(EcompUser ecompUser) { + User convertedUser = new User(); + + if (ecompUser == null) { + return Either.right("EcompUser is null"); + } + + convertedUser.setFirstName(ecompUser.getFirstName()); + convertedUser.setLastName(ecompUser.getLastName()); + + if (!ecompUser.getLoginId().isEmpty()) { + convertedUser.setUserId(ecompUser.getLoginId()); + } else { + convertedUser.setUserId(ecompUser.getOrgUserId()); + } + + convertedUser.setEmail(ecompUser.getEmail()); + + if (ecompUser.getRoles() != null) { + Iterator<EcompRole> iter = ecompUser.getRoles().iterator(); + + if (iter.hasNext()) { + String updatedRole = EcompRoleConverter.convertEcompRoleToRole(iter.next()); + convertedUser.setRole(updatedRole); + } + } + + if (ecompUser.isActive()) { + convertedUser.setStatus(UserStatusEnum.ACTIVE); + } else { + convertedUser.setStatus(UserStatusEnum.INACTIVE); + } + + return Either.left(convertedUser); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/ArtifactExternalServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/ArtifactExternalServlet.java new file mode 100644 index 0000000000..ecdce79b29 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/ArtifactExternalServlet.java @@ -0,0 +1,646 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.servlets.BeGenericServlet; +import org.openecomp.sdc.be.servlets.RepresentationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +/** + * This Servlet serves external users operations on artifacts. + * + * @author mshitrit + * + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Singleton +public class ArtifactExternalServlet extends BeGenericServlet { + + @Context + private HttpServletRequest request; + + private static Logger log = LoggerFactory.getLogger(ArtifactExternalServlet.class.getName()); + + /** + * Uploads an artifact to resource or service + * + * @param assetType + * @param uuid + * @return + */ + @POST + @Path("/{assetType}/{uuid}/artifacts") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "uploads of artifact to a resource or service", httpMethod = "POST", notes = "uploads of artifact to a resource or service", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact uploaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response uploadArtifact(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @ApiParam(value = "json describe the artifact", required = true) String data) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + String userId = request.getHeader(Constants.USER_ID_HEADER); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("uploadArtifact: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("uploadArtifact: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty() && (userId == null || userId.isEmpty())) { + log.debug("uploadArtifact: Missing USER_ID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactEither = artifactsLogic.uploadArtifactToComponentByUUID(data, request, componentType, uuid, additionalParams); + if (uploadArtifactEither.isRight()) { + log.debug("failed to upload artifact"); + responseFormat = uploadArtifactEither.right().value(); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + Object representation = RepresentationUtils.toRepresentation(uploadArtifactEither.left().value()); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByString((String) representation)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation, headers)); + } + } catch (Exception e) { + final String message = "failed to upload artifact to a resource or service"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * Uploads an artifact to resource instance + * + * @param assetType + * @param uuid + * @param resourceInstanceName + * @return + */ + @POST + @Path("/{assetType}/{uuid}/resourceInstances/{resourceInstanceName}/artifacts") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "uploads an artifact to a resource instance", httpMethod = "POST", notes = "uploads an artifact to a resource instance", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact uploaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response uploadArtifactToInstance(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @PathParam("resourceInstanceName") final String resourceInstanceName, + @ApiParam(value = "json describe the artifact", required = true) String data) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + String userId = request.getHeader(Constants.USER_ID_HEADER); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("uploadArtifact: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("uploadArtifact: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty() && (userId == null || userId.isEmpty())) { + log.debug("uploadArtifact: Missing USER_ID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactEither = artifactsLogic.uploadArtifactToRiByUUID(data, request, componentType, uuid, resourceInstanceName, additionalParams); + if (uploadArtifactEither.isRight()) { + log.debug("failed to upload artifact"); + responseFormat = uploadArtifactEither.right().value(); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + Object representation = RepresentationUtils.toRepresentation(uploadArtifactEither.left().value()); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByString((String) representation)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalUploadArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation, headers)); + } + } catch (Exception e) { + final String message = "failed to upload artifact to a resource instance"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * updates an artifact on a resource or service + * + * @param assetType + * @param uuid + * @param artifactUUID + * @return + */ + @POST + @Path("/{assetType}/{uuid}/artifacts/{artifactUUID}") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "updates an artifact on a resource or service", httpMethod = "POST", notes = "uploads of artifact to a resource or service", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact Updated"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response updateArtifact(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @PathParam("artifactUUID") final String artifactUUID, + @ApiParam(value = "json describe the artifact", required = true) String data) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + String userId = request.getHeader(Constants.USER_ID_HEADER); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("updateArtifact: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + + // Mandatory + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("updateArtifact: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty() && (userId == null || userId.isEmpty())) { + log.debug("updateArtifact: Missing USER_ID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactEither = artifactsLogic.updateArtifactOnComponentByUUID(data, request, componentType, uuid, artifactUUID, additionalParams); + if (uploadArtifactEither.isRight()) { + log.debug("failed to update artifact"); + responseFormat = uploadArtifactEither.right().value(); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + Object representation = RepresentationUtils.toRepresentation(uploadArtifactEither.left().value()); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByString((String) representation)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation, headers)); + } + } catch (Exception e) { + final String message = "failed to update artifact on a resource or service"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * updates an artifact on a resource instance + * + * @param assetType + * @param uuid + * @param resourceInstanceName + * @param artifactUUID + * @return + */ + @POST + @Path("/{assetType}/{uuid}/resourceInstances/{resourceInstanceName}/artifacts/{artifactUUID}") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "updates an artifact on a resource instance", httpMethod = "POST", notes = "uploads of artifact to a resource or service", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact Updated"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response updateArtifactOnResourceInstance(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @PathParam("resourceInstanceName") final String resourceInstanceName, + @PathParam("artifactUUID") final String artifactUUID, @ApiParam(value = "json describe the artifact", required = true) String data) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + String userId = request.getHeader(Constants.USER_ID_HEADER); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("updateArtifactOnResourceInstance: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("updateArtifactOnResourceInstance: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty() && (userId == null || userId.isEmpty())) { + log.debug("updateArtifactOnResourceInstance: Missing USER_ID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactEither = artifactsLogic.updateArtifactOnRiByUUID(data, request, componentType, uuid, resourceInstanceName, artifactUUID, additionalParams); + if (uploadArtifactEither.isRight()) { + log.debug("failed to update artifact"); + responseFormat = uploadArtifactEither.right().value(); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + Object representation = RepresentationUtils.toRepresentation(uploadArtifactEither.left().value()); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByString((String) representation)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalUpdateArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation, headers)); + } + } catch (Exception e) { + final String message = "failed to update artifact on resource instance"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * deletes an artifact of a resource or service + * + * @param assetType + * @param uuid + * @param artifactUUID + * @return + */ + @DELETE + @Path("/{assetType}/{uuid}/artifacts/{artifactUUID}") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "deletes an artifact of a resource or service", httpMethod = "DELETE", notes = "deletes an artifact of a resource or service", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact Deleted"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response deleteArtifact(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @PathParam("artifactUUID") final String artifactUUID) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + String requestURI = request.getRequestURI(); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("deleteArtifact: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("deleteArtifact: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty() && (userId == null || userId.isEmpty())) { + log.debug("deleteArtifact: Missing USER_ID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactEither = artifactsLogic.deleteArtifactOnComponentByUUID(request, componentType, uuid, artifactUUID, additionalParams); + if (uploadArtifactEither.isRight()) { + log.debug("failed to delete artifact"); + responseFormat = uploadArtifactEither.right().value(); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + Object representation = RepresentationUtils.toRepresentation(uploadArtifactEither.left().value()); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByString((String) representation)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation, headers)); + } + } catch (Exception e) { + final String message = "failed to delete an artifact of a resource or service"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * deletes an artifact of a resource instance + * + * @param assetType + * @param uuid + * @param resourceInstanceName + * @return + */ + @DELETE + @Path("{assetType}/{uuid}/resourceInstances/{resourceInstanceName}/artifacts/{artifactUUID}") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "deletes an artifact of a resource insatnce", httpMethod = "DELETE", notes = "deletes an artifact of a resource insatnce", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact Deleted"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response deleteArtifactOnResourceInstance(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @PathParam("resourceInstanceName") final String resourceInstanceName, + @PathParam("artifactUUID") final String artifactUUID) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String userId = request.getHeader(Constants.USER_ID_HEADER); + String requestURI = request.getRequestURI(); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("deleteArtifactOnResourceInsatnce: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("deleteArtifactOnResourceInsatnce: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty() && (userId == null || userId.isEmpty())) { + log.debug("deleteArtifactOnResourceInsatnce: Missing USER_ID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CONTACT); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ArtifactDefinition, ResponseFormat> uploadArtifactEither = artifactsLogic.deleteArtifactOnRiByUUID(request, componentType, uuid, resourceInstanceName, artifactUUID, additionalParams); + if (uploadArtifactEither.isRight()) { + log.debug("failed to delete artifact"); + responseFormat = uploadArtifactEither.right().value(); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + Object representation = RepresentationUtils.toRepresentation(uploadArtifactEither.left().value()); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByString((String) representation)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalDeleteArtifact(responseFormat, componentType.getValue(), request, additionalParams); + responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation, headers)); + } + } catch (Exception e) { + final String message = "failed to delete an artifact of a resource instance"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * downloads an artifact of a component (either a service or a resource) by artifactUUID + * + * @param assetType + * @param uuid + * @param artifactUUID + * @return + */ + @GET + @Path("/{assetType}/{uuid}/artifacts/{artifactUUID}") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download component artifact", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact downloaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Artifact not found") }) + public Response downloadComponentArtifact( + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType, + @PathParam("uuid") final String uuid, @PathParam("artifactUUID") final String artifactUUID) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("downloadComponentArtifact: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("downloadComponentArtifact: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalDownloadArtifact(responseFormat, componentType.getValue(), request, additionalParam); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<byte[], ResponseFormat> downloadComponentArtifactEither = artifactsLogic.downloadComponentArtifactByUUIDs(componentType, uuid, artifactUUID, additionalParam); + if (downloadComponentArtifactEither.isRight()) { + responseFormat = downloadComponentArtifactEither.right().value(); + getComponentsUtils().auditExternalDownloadArtifact(responseFormat, componentType.getValue(), request, additionalParam); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + byte[] value = downloadComponentArtifactEither.left().value(); + InputStream is = new ByteArrayInputStream(value); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByByteArray(value)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalDownloadArtifact(responseFormat, componentType.getValue(), request, additionalParam); + responseWrapper.setInnerElement(buildOkResponse(responseFormat, is, headers)); + } + } catch (Exception e) { + final String message = "failed to download an artifact of a resource or service"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } + + /** + * downloads an artifact of a resource instance of a component (either a service or a resource) by artifactUUID + * + * @param assetType + * @param uuid + * @param resourceInstanceName + * @param artifactUUID + * @return + */ + @GET + @Path("/{assetType}/{uuid}/resourceInstances/{resourceInstanceName}/artifacts/{artifactUUID}") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download resource instance artifact", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact downloaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Artifact not found") }) + public Response downloadResourceInstanceArtifact( + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType, + @PathParam("uuid") final String uuid, @PathParam("resourceInstanceName") final String resourceInstanceName, @PathParam("artifactUUID") final String artifactUUID) { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + ResponseFormat responseFormat; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + if (componentType == null) { + log.debug("downloadResourceInstanceArtifact: assetType parameter {} is not valid", assetType); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<>(AuditingFieldsKeysEnum.class); + + if (responseWrapper.isEmpty() && (instanceIdHeader == null || instanceIdHeader.isEmpty())) { + log.debug("downloadResourceInstanceArtifact: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalDownloadArtifact(responseFormat, componentType.getValue(), request, additionalParam); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } + if (responseWrapper.isEmpty()) { + try { + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<byte[], ResponseFormat> downloadResourceArtifactEither = artifactsLogic.downloadResourceInstanceArtifactByUUIDs(componentType, uuid, resourceInstanceName, artifactUUID, additionalParam); + if (downloadResourceArtifactEither.isRight()) { + responseFormat = downloadResourceArtifactEither.right().value(); + getComponentsUtils().auditExternalDownloadArtifact(responseFormat, componentType.getValue(), request, additionalParam); + responseWrapper.setInnerElement(buildErrorResponse(responseFormat)); + } else { + byte[] value = downloadResourceArtifactEither.left().value(); + InputStream is = new ByteArrayInputStream(value); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.MD5_HEADER, GeneralUtility.calculateMD5ByByteArray(value)); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalDownloadArtifact(responseFormat, componentType.getValue(), request, additionalParam); + responseWrapper.setInnerElement(buildOkResponse(responseFormat, is, headers)); + } + } catch (Exception e) { + final String message = "failed to download an artifact of a resource instance"; + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message); + log.debug(message, e); + responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR))); + } + } + return responseWrapper.getInnerElement(); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetMetadataConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetMetadataConverter.java new file mode 100644 index 0000000000..20eac081c9 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetMetadataConverter.java @@ -0,0 +1,381 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.distribution.servlet.DistributionCatalogServlet; +import org.openecomp.sdc.be.externalapi.servlet.representation.ArtifactMetadata; +import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata; +import org.openecomp.sdc.be.externalapi.servlet.representation.ResourceAssetDetailedMetadata; +import org.openecomp.sdc.be.externalapi.servlet.representation.ResourceAssetMetadata; +import org.openecomp.sdc.be.externalapi.servlet.representation.ResourceInstanceMetadata; +import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceAssetDetailedMetadata; +import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceAssetMetadata; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import fj.data.Either; + +@org.springframework.stereotype.Component("asset-metadata-utils") +public class AssetMetadataConverter { + private static Logger log = LoggerFactory.getLogger(DistributionCatalogServlet.class.getName()); + + @Autowired + private ComponentsUtils componentsUtils; + @Autowired + private ResourceOperation resourceOperation; + + /* + * Relative asset’s URL. Should be used in REST GET API to download the asset’s CSAR. https://{serverBaseURL}/{csarPath} can be obtained from (HttpServletRequest)request.getServerName() + */ + public Either<List<? extends AssetMetadata>, ResponseFormat> convertToAssetMetadata(List<? extends Component> componentList, String serverBaseURL, boolean detailed) { + if (componentList == null || componentList.isEmpty()) { + return Either.left(new LinkedList<>()); + } + + List<AssetMetadata> retResList = new LinkedList<>(); + Component component = componentList.iterator().next(); + ComponentTypeEnum componentType = component.getComponentType(); + + for (Component curr : componentList) { + + Either<? extends AssetMetadata, ResponseFormat> resMetaData = convertToMetadata(componentType, serverBaseURL, detailed, curr); + + if (resMetaData.isRight()) { + return Either.right(resMetaData.right().value()); + } + + retResList.add(resMetaData.left().value()); + } + + return Either.left(retResList); + + } + + private Either<? extends AssetMetadata, ResponseFormat> convertToMetadata(ComponentTypeEnum componentType, String serverBaseURL, boolean detailed, Component curr) { + + switch (componentType) { + + case RESOURCE: + + return generateResourceMeatdata(serverBaseURL, detailed, curr); + + case SERVICE: + + return generateServiceMetadata(serverBaseURL, detailed, curr); + + // For future US's that include product + /* + * case PRODUCT: if (component instanceof Product) { List<ProductAssetMetadata> retResList = new LinkedList<>(); for (Component curr : componentList) { retResList.add(convertToProductAssetMetadata((Product) curr, serverBaseURL)); } return + * Either.left(retResList); + */ + default: + + ResponseFormat responseFormat = componentsUtils.getResponseFormatAdditionalProperty(ActionStatus.COMPONENT_INVALID_CATEGORY); + return Either.right(responseFormat); + } + } + + private Either<? extends AssetMetadata, ResponseFormat> generateResourceMeatdata(String serverBaseURL, boolean detailed, Component curr) { + AssetMetadata metaData; + metaData = createMetadaObject(detailed, curr.getComponentType()); + metaData = convertToResourceMetadata((ResourceAssetMetadata) metaData, (Resource) curr, serverBaseURL, detailed); + + if (detailed) { + Either<ResourceAssetDetailedMetadata, StorageOperationStatus> converted = convertToResourceDetailedMetadata((ResourceAssetDetailedMetadata) metaData, (Resource) curr, serverBaseURL); + if (converted.isRight()) { + ActionStatus storageResponse = componentsUtils.convertFromStorageResponse(converted.right().value(), ComponentTypeEnum.RESOURCE); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(storageResponse); + return Either.right(responseFormat); + } + } + + return Either.left(metaData); + } + + private AssetMetadata createMetadaObject(boolean detailed, ComponentTypeEnum type) { + AssetMetadata metaData = null; + switch (type) { + case SERVICE: + if (!detailed) { + metaData = new ServiceAssetMetadata(); + } else { + metaData = new ServiceAssetDetailedMetadata(); + } + break; + case RESOURCE: + if (!detailed) { + metaData = new ResourceAssetMetadata(); + } else { + metaData = new ResourceAssetDetailedMetadata(); + } + break; + default: + break; + } + return metaData; + } + + private Either<? extends AssetMetadata, ResponseFormat> generateServiceMetadata(String serverBaseURL, boolean detailed, Component curr) { + AssetMetadata metaData = createMetadaObject(detailed, curr.getComponentType()); + + metaData = convertToServiceAssetMetadata((ServiceAssetMetadata) metaData, (Service) curr, serverBaseURL, detailed); + + if (detailed) { + Either<ServiceAssetDetailedMetadata, StorageOperationStatus> converted = convertToServiceDetailedMetadata((ServiceAssetDetailedMetadata) metaData, (Service) curr, serverBaseURL); + if (converted.isRight()) { + ActionStatus storageResponse = componentsUtils.convertFromStorageResponse(converted.right().value(), ComponentTypeEnum.RESOURCE); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(storageResponse); + return Either.right(responseFormat); + } + } + + return Either.left(metaData); + } + + private <U extends AssetMetadata, T extends Component> U convertToAsset(U asset, T component, String serverBaseURL, boolean detailed) { + asset.setUuid(component.getUUID()); + asset.setInvariantUUID(component.getInvariantUUID()); + asset.setName(component.getName()); + asset.setVersion(component.getVersion()); + if (!detailed) { + asset.setToscaModelURL(serverBaseURL + "/" + component.getUUID() + "/toscaModel"); + } else { + String toscaModelUrl = (new String(serverBaseURL)).replace("metadata", "toscaModel"); + asset.setToscaModelURL(toscaModelUrl); + } + + return asset; + } + + private <T extends ResourceAssetMetadata> T convertToResourceMetadata(T assetToPopulate, Resource resource, String serverBaseURL, boolean detailed) { + assetToPopulate = convertToAsset(assetToPopulate, resource, serverBaseURL, detailed); + CategoryDefinition categoryDefinition = resource.getCategories().iterator().next(); + assetToPopulate.setCategory(categoryDefinition.getName()); + + SubCategoryDefinition subCategoryDefinition = categoryDefinition.getSubcategories().iterator().next(); + + assetToPopulate.setSubCategory(subCategoryDefinition.getName()); + assetToPopulate.setResourceType(resource.getResourceType().name()); + assetToPopulate.setLifecycleState(resource.getLifecycleState().name()); + assetToPopulate.setLastUpdaterUserId(resource.getLastUpdaterUserId()); + + return (T) assetToPopulate; + } + + private <T extends ServiceAssetMetadata> T convertToServiceAssetMetadata(T assetToPopulate, Service service, String serverBaseURL, boolean detailed) { + assetToPopulate = convertToAsset(assetToPopulate, service, serverBaseURL, detailed); + + CategoryDefinition categoryDefinition = service.getCategories().iterator().next(); + + assetToPopulate.setCategory(categoryDefinition.getName()); + assetToPopulate.setLifecycleState(service.getLifecycleState().name()); + assetToPopulate.setLastUpdaterUserId(service.getLastUpdaterUserId()); + assetToPopulate.setDistributionStatus(service.getDistributionStatus().name()); + + return (T) assetToPopulate; + } + + private <T extends ResourceAssetDetailedMetadata> Either<T, StorageOperationStatus> convertToResourceDetailedMetadata(T assetToPopulate, Resource resource, String serverBaseURL) { + + List<ComponentInstance> componentInstances = resource.getComponentInstances(); + + if (componentInstances != null) { + Either<List<ResourceInstanceMetadata>, StorageOperationStatus> resourceInstanceMetadata = convertToResourceInstanceMetadata(componentInstances, ComponentTypeEnum.RESOURCE_PARAM_NAME, resource.getUUID()); + if (resourceInstanceMetadata.isRight()) { + return Either.right(resourceInstanceMetadata.right().value()); + } + + assetToPopulate.setResources(resourceInstanceMetadata.left().value()); + } + + Map<String, ArtifactDefinition> deploymentArtifacts = resource.getDeploymentArtifacts(); + assetToPopulate = populateResourceWithArtifacts(assetToPopulate, resource, serverBaseURL, deploymentArtifacts); + + assetToPopulate.setLastUpdaterFullName(resource.getLastUpdaterFullName()); + assetToPopulate.setToscaResourceName(resource.getToscaResourceName()); + + return Either.left(assetToPopulate); + } + + private <T extends ServiceAssetDetailedMetadata> Either<T, StorageOperationStatus> convertToServiceDetailedMetadata(T assetToPopulate, Service service, String serverBaseURL) { + + List<ComponentInstance> componentInstances = service.getComponentInstances(); + + if (componentInstances != null) { + Either<List<ResourceInstanceMetadata>, StorageOperationStatus> resourceInstanceMetadata = convertToResourceInstanceMetadata(componentInstances, ComponentTypeEnum.SERVICE_PARAM_NAME, service.getUUID()); + if (resourceInstanceMetadata.isRight()) { + return Either.right(resourceInstanceMetadata.right().value()); + } + + assetToPopulate.setResources(resourceInstanceMetadata.left().value()); + } + + Map<String, ArtifactDefinition> deploymentArtifacts = service.getDeploymentArtifacts(); + assetToPopulate = populateServiceWithArtifacts(assetToPopulate, service, deploymentArtifacts); + + assetToPopulate.setLastUpdaterFullName(service.getLastUpdaterFullName()); + + return Either.left(assetToPopulate); + } + + private <T extends ResourceAssetDetailedMetadata> T populateResourceWithArtifacts(T asset, Resource resource, String serverBaseURL, Map<String, ArtifactDefinition> artifacts) { + + List<ArtifactMetadata> artifactMetaList = populateAssetWithArtifacts(resource, artifacts); + + asset.setArtifacts(artifactMetaList); + + return asset; + } + + private <T extends ServiceAssetDetailedMetadata> T populateServiceWithArtifacts(T asset, Service service, Map<String, ArtifactDefinition> artifacts) { + + List<ArtifactMetadata> artifactMetaList = populateAssetWithArtifacts(service, artifacts); + + asset.setArtifacts(artifactMetaList); + + return asset; + } + + private List<ArtifactMetadata> populateAssetWithArtifacts(Component component, Map<String, ArtifactDefinition> artifacts) { + List<ArtifactMetadata> artifactMetaList = null; + if (artifacts != null) { + artifactMetaList = new LinkedList<>(); + Collection<ArtifactDefinition> artefactDefList = artifacts.values(); + + for (ArtifactDefinition artifactDefinition : artefactDefList) { + if (artifactDefinition.getEsId() != null && !artifactDefinition.getEsId().isEmpty()) { + ArtifactMetadata convertedArtifactMetadata = convertToArtifactMetadata(artifactDefinition, ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUUID(), null); + artifactMetaList.add(convertedArtifactMetadata); + } + } + } + return artifactMetaList.isEmpty() ? null : artifactMetaList; + } + + private ArtifactMetadata convertToArtifactMetadata(ArtifactDefinition artifact, String componentType, String componentUUID, String resourceInstanceName) { + // /asdc/v1/catalog/{services/resources}/{componentUUID}/artifacts/{artifactUUID} + final String COMPONENT_ARTIFACT_URL = "/asdc/v1/catalog/%s/%s/artifacts/%s"; + + // /asdc/v1/catalog/{services/resources}/{componentUUID}/resourceInstances/{resourceInstanceName}/artifacts/{artifactUUID} + final String RESOURCE_INSTANCE_ARTIFACT_URL = "/asdc/v1/catalog/%s/%s/resourceInstances/%s/artifacts/%s"; + + ArtifactMetadata metadata = new ArtifactMetadata(); + + metadata.setArtifactName(artifact.getArtifactName()); + metadata.setArtifactType(artifact.getArtifactType()); + + if (resourceInstanceName == null || resourceInstanceName.isEmpty()) { + metadata.setArtifactURL(String.format(COMPONENT_ARTIFACT_URL, componentType, componentUUID, artifact.getArtifactUUID())); + } else { + metadata.setArtifactURL(String.format(RESOURCE_INSTANCE_ARTIFACT_URL, componentType, componentUUID, resourceInstanceName, artifact.getArtifactUUID())); + } + + metadata.setArtifactDescription(artifact.getDescription()); + metadata.setArtifactTimeout(artifact.getTimeout() > 0 ? artifact.getTimeout() : null); + metadata.setArtifactChecksum(artifact.getArtifactChecksum()); + metadata.setArtifactUUID(artifact.getArtifactUUID()); + metadata.setArtifactVersion(artifact.getArtifactVersion()); + metadata.setGeneratedFromUUID(artifact.getGeneratedFromId()); + + return metadata; + } + + private Either<List<ResourceInstanceMetadata>, StorageOperationStatus> convertToResourceInstanceMetadata(List<ComponentInstance> componentInstances, String componentType, String componentUUID) { + List<ResourceInstanceMetadata> retList = new LinkedList<>(); + Map<String, String> uuidDuplicatesMap = new HashMap<>(); + + for (ComponentInstance componentInstance : componentInstances) { + ResourceInstanceMetadata metadata = new ResourceInstanceMetadata(); + String componentUid = componentInstance.getComponentUid(); + String invariantUUID; + + if (!uuidDuplicatesMap.containsKey(componentUid)) { + Either<String, StorageOperationStatus> getInvarUuidresponse = resourceOperation.getInvariantUUID(NodeTypeEnum.Resource, componentInstance.getComponentUid(), false); + if (getInvarUuidresponse.isRight()) { + log.debug("convertToResourceInstanceMetadata: Failed getting Invariant UUID"); + return Either.right(getInvarUuidresponse.right().value()); + } else { + invariantUUID = getInvarUuidresponse.left().value(); + uuidDuplicatesMap.put(componentUid, invariantUUID); + } + } else { + invariantUUID = uuidDuplicatesMap.get(componentUid); + } + + metadata.setResourceInvariantUUID(invariantUUID); + metadata.setResourceInstanceName(componentInstance.getName()); + metadata.setResourceName(componentInstance.getComponentName()); + metadata.setResourceVersion(componentInstance.getComponentVersion()); + metadata.setResoucreType(componentInstance.getOriginType().getValue()); + metadata.setResourceUUID(componentInstance.getComponentUid()); + + Collection<ArtifactDefinition> values = componentInstance.getDeploymentArtifacts().values(); + LinkedList<ArtifactMetadata> artifactMetaList = new LinkedList<>(); + + for (ArtifactDefinition artifactDefinition : values) { + ArtifactMetadata converted = convertToArtifactMetadata(artifactDefinition, componentType, componentUUID, componentInstance.getNormalizedName()); + artifactMetaList.add(converted); + } + + metadata.setArtifacts(artifactMetaList); + + retList.add(metadata); + } + + return Either.left(retList); + } + + // For future US to support Product + /* + * private ProductAssetMetadata convertToProductAssetMetadata(Product product, String serverBaseURL) { ProductAssetMetadata retProdAsset = new ProductAssetMetadata(); + * + * retProdAsset = convertToAsset(retProdAsset, product, serverBaseURL); retProdAsset.setLifecycleState(product.getLifecycleState().name()); retProdAsset.setLastUpdaterUserId(product.getLastUpdaterUserId()); + * retProdAsset.setActive(product.getIsActive()); retProdAsset.setContacts(product.getContacts()); + * + * List<CategoryDefinition> categories = product.getCategories(); List<ProductCategoryGroupMetadata> categoryMetadataList = new LinkedList<>(); + * + * if (categories == null || categories.isEmpty()) { return retProdAsset; } else { for (CategoryDefinition categoryDefinition : categories) { String categoryName = categoryDefinition.getName(); List<SubCategoryDefinition> subcategories = + * categoryDefinition.getSubcategories(); for (SubCategoryDefinition subCategoryDefinition : subcategories) { String subCategoryName = subCategoryDefinition.getName(); List<GroupDefinition> groups = product.getGroups(); for (GroupDefinition + * groupDefinition : groups) { String groupName = groupDefinition.getName(); categoryMetadataList.add(new ProductCategoryGroupMetadata(categoryName, subCategoryName, groupName)); } } } retProdAsset.setProductGroupings(categoryMetadataList); + * return retProdAsset; } } + */ +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java new file mode 100644 index 0000000000..1b8d6fdb75 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java @@ -0,0 +1,300 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.http.NameValuePair; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.impl.ElementBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; +import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.servlets.BeGenericServlet; +import org.openecomp.sdc.be.servlets.RepresentationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Singleton +public class AssetsDataServlet extends BeGenericServlet { + + @Context + private HttpServletRequest request; + + private AssetMetadataConverter assetMetadataUtils; + private static Logger log = LoggerFactory.getLogger(AssetsDataServlet.class.getName()); + + @GET + @Path("/{assetType}") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Fetch list of assets", httpMethod = "GET", notes = "Returns list of assets", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), @ApiResponse(code = 401, message = "Authorization required"), + @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Asset not found") }) + public Response getAssetList(@PathParam("assetType") final String assetType, @QueryParam("category") String category, @QueryParam("subCategory") String subCategory, @QueryParam("distributionStatus") String distributionStatus) { + + Response response = null; + ResponseFormat responseFormat = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String query = request.getQueryString(); + String requestURI = request.getRequestURI(); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + String serverBaseURL = request.getRequestURL().toString(); + + AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST; + + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, query == null ? requestURI : requestURI + "?" + query); + + // Mandatory + if (instanceIdHeader == null || instanceIdHeader.isEmpty()) { + log.debug("getAssetList: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + + try { + ServletContext context = request.getSession().getServletContext(); + ElementBusinessLogic elementLogic = getElementBL(context); + + getAssetUtils(context); + Map<FilterKeyEnum, String> filters = new HashMap<FilterKeyEnum, String>(); + + if (category != null) { + filters.put(FilterKeyEnum.CATEGORY, category); + } + if (subCategory != null) { + filters.put(FilterKeyEnum.SUB_CATEGORY, subCategory); + } + if (distributionStatus != null) { + filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus); + } + + Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getFilteredCatalogComponents(assetType, filters, query); + + if (assetTypeData.isRight()) { + log.debug("getAssetList: Asset Fetching Failed"); + responseFormat = assetTypeData.right().value(); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } else { + log.debug("getAssetList: Asset Fetching Success"); + Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), serverBaseURL, false); + if (resMetadata.isRight()) { + log.debug("getAssetList: Asset conversion Failed"); + responseFormat = resMetadata.right().value(); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + Object result = RepresentationUtils.toRepresentation(resMetadata.left().value()); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + + response = buildOkResponse(responseFormat, result); + return response; + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets"); + log.debug("getAssetList: Fetch list of assets failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/{assetType}/{uuid}/metadata") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Fetch metadata of asset by uuid", httpMethod = "GET", notes = "Returns metadata of asset", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response getAssetListByUuid(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @Context final HttpServletRequest request) { + + Response response = null; + ResponseFormat responseFormat = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA; + String requestURI = request.getRequestURI(); + String url = request.getMethod() + " " + requestURI; + log.debug("Start handle request of {}", url); + String serverBaseURL = request.getRequestURL().toString(); + + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue()); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid); + + // Mandatory + if (instanceIdHeader == null || instanceIdHeader.isEmpty()) { + log.debug("getAssetList: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + + try { + ServletContext context = request.getSession().getServletContext(); + ElementBusinessLogic elementLogic = getElementBL(context); + getAssetUtils(context); + + Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid); + + if (assetTypeData.isRight()) { + log.debug("getAssetList: Asset Fetching Failed"); + responseFormat = assetTypeData.right().value(); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + + return buildErrorResponse(responseFormat); + } else { + log.debug("getAssetList: Asset Fetching Success"); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, assetTypeData.left().value().iterator().next().getName()); + Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), serverBaseURL, true); + if (resMetadata.isRight()) { + log.debug("getAssetList: Asset conversion Failed"); + responseFormat = resMetadata.right().value(); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + Object result = RepresentationUtils.toRepresentation(resMetadata.left().value().iterator().next()); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + + response = buildOkResponse(responseFormat, result); + return response; + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets"); + log.debug("getAssetList: Fetch list of assets failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private void getAssetUtils(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + assetMetadataUtils = webApplicationContext.getBean(AssetMetadataConverter.class); + } + + @GET + @Path("/{assetType}/{uuid}/toscaModel") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Fetch asset csar", httpMethod = "GET", notes = "Returns asset csar", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Asset Model Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Asset not found") }) + public Response getToscaModel(@PathParam("uuid") final String uuid, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType, + @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization) { + + String url = request.getRequestURI(); + log.debug("Start handle request of {} {}", request.getMethod(), url); + Response response = null; + ResponseFormat responseFormat = null; + ServletContext context = request.getSession().getServletContext(); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType); + AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_TOSCA_MODEL; + String userId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, userId); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, url); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue()); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid); + + if (userId == null || userId.isEmpty()) { + log.debug("getToscaModel: Missing X-ECOMP-InstanceID header"); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return buildErrorResponse(responseFormat); + } + + try { + ComponentBusinessLogic componentBL = getComponentBL(componentType, context); + + Either<ImmutablePair<String, byte[]>, ResponseFormat> csarArtifact = componentBL.getToscaModelByComponentUuid(componentType, uuid, additionalParam); + if (csarArtifact.isRight()) { + responseFormat = csarArtifact.right().value(); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + response = buildErrorResponse(responseFormat); + } else { + byte[] value = csarArtifact.left().value().getRight(); + InputStream is = new ByteArrayInputStream(value); + String contenetMD5 = GeneralUtility.calculateMD5ByByteArray(value); + Map<String, String> headers = new HashMap<>(); + headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(csarArtifact.left().value().getLeft())); + headers.put(Constants.MD5_HEADER, contenetMD5); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + response = buildOkResponse(responseFormat, is, headers); + } + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get asset tosca model"); + log.debug("falied to get asset tosca model", e); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + response = buildErrorResponse(responseFormat); + getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam); + return response; + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ArtifactMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ArtifactMetadata.java new file mode 100644 index 0000000000..f4194cf2f5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ArtifactMetadata.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +public class ArtifactMetadata { + private String artifactName; + private String artifactType; + private String artifactURL; + private String artifactDescription; + private Integer artifactTimeout; + private String artifactChecksum; + private String artifactUUID; + private String artifactVersion; + private String generatedFromUUID; + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + public String getArtifactURL() { + return artifactURL; + } + + public void setArtifactURL(String artifactURL) { + this.artifactURL = artifactURL; + } + + public String getArtifactDescription() { + return artifactDescription; + } + + public void setArtifactDescription(String artifactDescription) { + this.artifactDescription = artifactDescription; + } + + public Integer getArtifactTimeout() { + return artifactTimeout; + } + + public void setArtifactTimeout(Integer artifactTimeout) { + this.artifactTimeout = artifactTimeout; + } + + public String getArtifactChecksum() { + return artifactChecksum; + } + + public void setArtifactChecksum(String artifactChecksum) { + this.artifactChecksum = artifactChecksum; + } + + public String getArtifactUUID() { + return artifactUUID; + } + + public void setArtifactUUID(String artifactUUID) { + this.artifactUUID = artifactUUID; + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public String getGeneratedFromUUID() { + return generatedFromUUID; + } + + public void setGeneratedFromUUID(String generatedFromUUID) { + this.generatedFromUUID = generatedFromUUID; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/AssetMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/AssetMetadata.java new file mode 100644 index 0000000000..cb14f76aff --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/AssetMetadata.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +public abstract class AssetMetadata implements IAssetMetadata { + private String uuid; + private String invariantUUID; + private String name; + private String version; + private String toscaModelURL; + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# getUuid() + */ + @Override + public String getUuid() { + return uuid; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# setUuid(java.lang.String) + */ + @Override + public void setUuid(String uuid) { + this.uuid = uuid; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# getInvariantUUID() + */ + @Override + public String getInvariantUUID() { + return invariantUUID; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# setInvariantUUID(java.lang.String) + */ + @Override + public void setInvariantUUID(String invariantUUID) { + this.invariantUUID = invariantUUID; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# getName() + */ + @Override + public String getName() { + return name; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# setName(java.lang.String) + */ + @Override + public void setName(String name) { + this.name = name; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# getVersion() + */ + @Override + public String getVersion() { + return version; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# setVersion(java.lang.String) + */ + @Override + public void setVersion(String version) { + this.version = version; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# toscaModelURL() + */ + @Override + public String getToscaModelURL() { + return toscaModelURL; + } + + /* + * (non-Javadoc) + * + * @see org.openecomp.sdc.be.distribution.servlet.representation.IAssetMetadata# toscaModelURL(java.lang.String) + */ + @Override + public void setToscaModelURL(String toscaModelURL) { + this.toscaModelURL = toscaModelURL; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/IAssetMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/IAssetMetadata.java new file mode 100644 index 0000000000..f95a8e9684 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/IAssetMetadata.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +public interface IAssetMetadata { + + String getUuid(); + + void setUuid(String uuid); + + String getInvariantUUID(); + + void setInvariantUUID(String invariantUUID); + + String getName(); + + void setName(String name); + + String getVersion(); + + void setVersion(String version); + + String getToscaModelURL(); + + void setToscaModelURL(String toscaModelURL); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ProductAssetMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ProductAssetMetadata.java new file mode 100644 index 0000000000..d2d9c2c902 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ProductAssetMetadata.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +import java.util.List; + +public class ProductAssetMetadata extends AssetMetadata { + private String lifecycleState; + private String lastUpdaterUserId; + private boolean isActive; + private List<String> contacts; + private List<ProductCategoryGroupMetadata> productGroupings; + + public String getLifecycleState() { + return lifecycleState; + } + + public void setLifecycleState(String lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean isActive) { + this.isActive = isActive; + } + + public List<String> getContacts() { + return contacts; + } + + public void setContacts(List<String> contacts) { + this.contacts = contacts; + } + + public List<ProductCategoryGroupMetadata> getProductGroupings() { + return productGroupings; + } + + public void setProductGroupings(List<ProductCategoryGroupMetadata> productGroupings) { + this.productGroupings = productGroupings; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ProductCategoryGroupMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ProductCategoryGroupMetadata.java new file mode 100644 index 0000000000..047f9d6a2c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ProductCategoryGroupMetadata.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +public class ProductCategoryGroupMetadata { + private String category; + private String subCategory; + private String group; + + public ProductCategoryGroupMetadata(String category, String subCategory, String group) { + this.category = category; + this.subCategory = subCategory; + this.group = group; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSubCategory() { + return subCategory; + } + + public void setSubCategory(String subCategory) { + this.subCategory = subCategory; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceAssetDetailedMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceAssetDetailedMetadata.java new file mode 100644 index 0000000000..ea282ec2e8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceAssetDetailedMetadata.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +import java.util.List; + +public class ResourceAssetDetailedMetadata extends ResourceAssetMetadata { + + private String lastUpdaterFullName; + private String toscaResourceName; + private List<ResourceInstanceMetadata> resources; + private List<ArtifactMetadata> artifacts; + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public String getToscaResourceName() { + return toscaResourceName; + } + + public void setToscaResourceName(String toscaResourceName) { + this.toscaResourceName = toscaResourceName; + } + + public List<ResourceInstanceMetadata> getResources() { + return resources; + } + + public void setResources(List<ResourceInstanceMetadata> resources) { + this.resources = resources; + } + + public List<ArtifactMetadata> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<ArtifactMetadata> artifactMetaList) { + this.artifacts = artifactMetaList; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceAssetMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceAssetMetadata.java new file mode 100644 index 0000000000..2b75facc6c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceAssetMetadata.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +public class ResourceAssetMetadata extends AssetMetadata { + private String category; + private String subCategory; + private String resourceType; + private String lifecycleState; + private String lastUpdaterUserId; + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSubCategory() { + return subCategory; + } + + public void setSubCategory(String subCategory) { + this.subCategory = subCategory; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public String getLifecycleState() { + return lifecycleState; + } + + public void setLifecycleState(String lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceInstanceMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceInstanceMetadata.java new file mode 100644 index 0000000000..a53422f311 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ResourceInstanceMetadata.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +import java.util.List; + +public class ResourceInstanceMetadata { + private String resourceInstanceName; + private String resourceName; + private String resourceInvariantUUID; + private String resourceVersion; + private String resoucreType; + private String resourceUUID; + private List<ArtifactMetadata> artifacts; + + public String getResourceInstanceName() { + return resourceInstanceName; + } + + public void setResourceInstanceName(String resourceInstanceName) { + this.resourceInstanceName = resourceInstanceName; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getResourceInvariantUUID() { + return resourceInvariantUUID; + } + + public void setResourceInvariantUUID(String resourceInvariantUUID) { + this.resourceInvariantUUID = resourceInvariantUUID; + } + + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + public String getResoucreType() { + return resoucreType; + } + + public void setResoucreType(String resoucreType) { + this.resoucreType = resoucreType; + } + + public String getResourceUUID() { + return resourceUUID; + } + + public void setResourceUUID(String resourceUUID) { + this.resourceUUID = resourceUUID; + } + + public List<ArtifactMetadata> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<ArtifactMetadata> artifacts) { + this.artifacts = artifacts; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceAssetDetailedMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceAssetDetailedMetadata.java new file mode 100644 index 0000000000..edd88b495d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceAssetDetailedMetadata.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +import java.util.List; + +public class ServiceAssetDetailedMetadata extends ServiceAssetMetadata { + private String lastUpdaterFullName; + private List<ResourceInstanceMetadata> resources; + private List<ArtifactMetadata> artifacts; + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public List<ResourceInstanceMetadata> getResources() { + return resources; + } + + public void setResources(List<ResourceInstanceMetadata> resources) { + this.resources = resources; + } + + public List<ArtifactMetadata> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<ArtifactMetadata> artifacts) { + this.artifacts = artifacts; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceAssetMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceAssetMetadata.java new file mode 100644 index 0000000000..094f973553 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceAssetMetadata.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +public class ServiceAssetMetadata extends AssetMetadata { + private String category; + private String lifecycleState; + private String lastUpdaterUserId; + private String distributionStatus; + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getLifecycleState() { + return lifecycleState; + } + + public void setLifecycleState(String lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } + + public String getDistributionStatus() { + return distributionStatus; + } + + public void setDistributionStatus(String distributionStatus) { + this.distributionStatus = distributionStatus; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BasicAuthenticationFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BasicAuthenticationFilter.java new file mode 100644 index 0000000000..f7e1d758ac --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BasicAuthenticationFilter.java @@ -0,0 +1,225 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.filters; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.StringTokenizer; + +import javax.annotation.Priority; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.codec.binary.Base64; +import org.openecomp.sdc.be.components.impl.ConsumerBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.ConsumerDefinition; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.exception.ResponseFormat; +import org.openecomp.sdc.security.Passwords; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import fj.data.Either; + +@Priority(10) +public class BasicAuthenticationFilter implements ContainerRequestFilter { + + @Context + private HttpServletRequest sr; + + protected Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + private String realm = "ASDC"; + + private static Logger log = LoggerFactory.getLogger(BasicAuthenticationFilter.class.getName()); + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + String authHeader = requestContext.getHeaderString(Constants.AUTHORIZATION_HEADER); + if (authHeader != null) { + StringTokenizer st = new StringTokenizer(authHeader); + if (st.hasMoreTokens()) { + String basic = st.nextToken(); + + if (basic.equalsIgnoreCase("Basic")) { + try { + String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8"); + log.debug("Credentials: {}", credentials); + checkUserCredentiles(requestContext, credentials); + } catch (UnsupportedEncodingException e) { + log.error("Authentication Filter Failed Couldn't retrieve authentication", e); + authInvalidHeaderError(requestContext); + } + } else { + log.error("Authentication Filter Failed Couldn't retrieve authentication, no basic autantication."); + authInvalidHeaderError(requestContext); + } + } else { + log.error("Authentication Filter Failed Couldn't retrieve authentication, no basic autantication."); + authInvalidHeaderError(requestContext); + } + + } else { + log.error("Authentication Filter Failed no autharization header"); + authRequiredError(requestContext); + } + } + + private void checkUserCredentiles(ContainerRequestContext requestContext, String credentials) { + int p = credentials.indexOf(":"); + if (p != -1) { + String _username = credentials.substring(0, p).trim(); + String _password = credentials.substring(p + 1).trim(); + + ConsumerBusinessLogic consumerBL = getConsumerBusinessLogic(); + if (consumerBL == null) { + log.error("Authentication Filter Failed to get consumerBL."); + requestContext.abortWith(Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build()); + } else { + Either<ConsumerDefinition, ResponseFormat> result = consumerBL.getConsumer(_username); + validatePassword(requestContext, _username, _password, result); + } + } else { + log.error("Authentication Filter Failed Couldn't retrieve authentication, no basic autantication."); + authInvalidHeaderError(requestContext); + + } + } + + private void validatePassword(ContainerRequestContext requestContext, String _username, String _password, Either<ConsumerDefinition, ResponseFormat> result) { + if (result.isRight()) { + Integer status = result.right().value().getStatus(); + if (status == Status.NOT_FOUND.getStatusCode()) { + log.error("Authentication Filter Failed Couldn't find user"); + authUserNotFoundError(requestContext, _username); + } else { + log.error("Authentication Filter Failed to get consumerBL."); + requestContext.abortWith(Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build()); + } + } else { + ConsumerDefinition consumerCredentials = result.left().value(); + if (!Passwords.isExpectedPassword(_password, consumerCredentials.getConsumerSalt(), consumerCredentials.getConsumerPassword())) { + log.error("Authentication Filter Failed invalide password"); + authInvalidePasswordError(requestContext, _username); + } else { + authSuccesessful(requestContext, _username); + } + } + } + + private void authSuccesessful(ContainerRequestContext requestContext, String _username) { + ComponentsUtils componentUtils = getComponentsUtils(); + if (componentUtils == null) { + log.error("Authentication Filter Failed to get component utils."); + requestContext.abortWith(Response.status(Status.INTERNAL_SERVER_ERROR).build()); + } + componentUtils.auditAuthEvent(AuditingActionEnum.AUTH_REQUEST, requestContext.getUriInfo().getPath(), _username, AuthStatus.AUTH_SUCCESS.toString(), realm); + } + + private void authInvalidePasswordError(ContainerRequestContext requestContext, String _username) { + ComponentsUtils componentUtils = getComponentsUtils(); + if (componentUtils == null) { + log.error("Authentication Filter Failed to get component utils."); + requestContext.abortWith(Response.status(Status.INTERNAL_SERVER_ERROR).build()); + } + componentUtils.auditAuthEvent(AuditingActionEnum.AUTH_REQUEST, requestContext.getUriInfo().getPath(), _username, AuthStatus.AUTH_FAILED_INVALID_PASSWORD.toString(), realm); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_FAILED); + requestContext.abortWith(buildErrorResponse(responseFormat, false)); + } + + private void authUserNotFoundError(ContainerRequestContext requestContext, String _username) { + ComponentsUtils componentUtils = getComponentsUtils(); + if (componentUtils == null) { + log.error("Authentication Filter Failed to get component utils."); + requestContext.abortWith(Response.status(Status.INTERNAL_SERVER_ERROR).build()); + } + getComponentsUtils().auditAuthEvent(AuditingActionEnum.AUTH_REQUEST, requestContext.getUriInfo().getPath(), _username, AuthStatus.AUTH_FAILED_USER_NOT_FOUND.toString(), realm); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_FAILED); + requestContext.abortWith(buildErrorResponse(responseFormat, false)); + } + + private void authInvalidHeaderError(ContainerRequestContext requestContext) { + ComponentsUtils componentUtils = getComponentsUtils(); + if (componentUtils == null) { + log.error("Authentication Filter Failed to get component utils."); + requestContext.abortWith(Response.status(Status.INTERNAL_SERVER_ERROR).build()); + } + getComponentsUtils().auditAuthEvent(AuditingActionEnum.AUTH_REQUEST, requestContext.getUriInfo().getPath(), "", AuthStatus.AUTH_FAILED_INVALID_AUTHENTICATION_HEADER.toString(), realm); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_FAILED_INVALIDE_HEADER); + requestContext.abortWith(buildErrorResponse(responseFormat, false)); + } + + private void authRequiredError(ContainerRequestContext requestContext) { + ComponentsUtils componentUtils = getComponentsUtils(); + if (componentUtils == null) { + log.error("Authentication Filter Failed to get component utils."); + requestContext.abortWith(Response.status(Status.INTERNAL_SERVER_ERROR).build()); + } + getComponentsUtils().auditAuthEvent(AuditingActionEnum.AUTH_REQUEST, requestContext.getUriInfo().getPath(), "", AuthStatus.AUTH_REQUIRED.toString(), realm); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_REQUIRED); + requestContext.abortWith(buildErrorResponse(responseFormat, true)); + } + + private ComponentsUtils getComponentsUtils() { + ServletContext context = sr.getSession().getServletContext(); + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + ComponentsUtils componentsUtils = webApplicationContext.getBean(ComponentsUtils.class); + return componentsUtils; + } + + private ConsumerBusinessLogic getConsumerBusinessLogic() { + ServletContext context = sr.getSession().getServletContext(); + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + ConsumerBusinessLogic consumerBusinessLogic = webApplicationContext.getBean(ConsumerBusinessLogic.class); + return consumerBusinessLogic; + } + + public enum AuthStatus { + AUTH_REQUIRED, AUTH_FAILED_USER_NOT_FOUND, AUTH_FAILED_INVALID_PASSWORD, AUTH_FAILED_INVALID_AUTHENTICATION_HEADER, AUTH_SUCCESS + } + + protected Response buildErrorResponse(ResponseFormat requestErrorWrapper, boolean addWwwAuthenticationHeader) { + ResponseBuilder responseBuilder = Response.status(requestErrorWrapper.getStatus()); + if (addWwwAuthenticationHeader) { + responseBuilder = responseBuilder.header("WWW-Authenticate", "Basic realm=\"" + realm + "\""); + } + Response response = responseBuilder.entity(gson.toJson(requestErrorWrapper.getRequestError())).build(); + return response; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeServletFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeServletFilter.java new file mode 100644 index 0000000000..f6c11d062e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeServletFilter.java @@ -0,0 +1,202 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.filters; + +import java.io.IOException; +import java.util.UUID; + +import javax.annotation.Priority; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.Configuration; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.util.ThreadLocalsHolder; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.GsonBuilder; + +@Provider +@Priority(1) +public class BeServletFilter implements ContainerRequestFilter, ContainerResponseFilter { + + @Context + private HttpServletRequest sr; + + private static Logger log = LoggerFactory.getLogger(BeServletFilter.class.getName()); + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + try { + + MDC.clear(); + + // In case of 405 response code, this function is not entered, then + // we'll process + // the MDC fields and UUID during the response + ThreadLocalsHolder.setMdcProcessed(true); + + // Timing HTTP request + ThreadLocalsHolder.setRequestStartTime(System.currentTimeMillis()); + + String uuid = processMdcFields(requestContext); + + ThreadLocalsHolder.setUuid(uuid); + + inHttpRequest(); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Error during request filter"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Error during request filter"); + log.debug("Error during request filter: {} ", e); + } + } + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { + try { + // Formatting the response in case of 405 + if (responseContext.getStatus() == Response.Status.METHOD_NOT_ALLOWED.getStatusCode()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_ALLOWED); + responseContext.setEntity(new GsonBuilder().setPrettyPrinting().create().toJson(responseFormat.getRequestError())); + } + + if (ThreadLocalsHolder.isMdcProcessed()) { + // filter() was executed during request - this is the regular + // flow + responseContext.getHeaders().add(Constants.X_ECOMP_REQUEST_ID_HEADER, ThreadLocalsHolder.getUuid()); + Long startTime = ThreadLocalsHolder.getRequestStartTime(); + if (startTime != null) { + long endTime = System.currentTimeMillis(); + MDC.put("timer", Long.toString(endTime - startTime)); + } + } else { + // this is the 405 response code case + // we have no MDC fields since filter() wasn't executed during + // request + String uuid = processMdcFields(requestContext); + responseContext.getHeaders().add(Constants.X_ECOMP_REQUEST_ID_HEADER, uuid); + } + + outHttpResponse(responseContext); + + // Cleaning up + MDC.clear(); + ThreadLocalsHolder.cleanup(); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Error during request filter"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Error during request filter"); + log.debug("Error during response filter: {} ", e); + } + } + + private String processMdcFields(ContainerRequestContext requestContext) { + // userId for logging + String userId = requestContext.getHeaderString(Constants.USER_ID_HEADER); + MDC.put("userId", userId); + + String serviceInstanceID = requestContext.getHeaderString(Constants.X_ECOMP_SERVICE_ID_HEADER); + MDC.put("serviceInstanceID", serviceInstanceID); + + MDC.put("remoteAddr", sr.getRemoteAddr()); + MDC.put("localAddr", sr.getLocalAddr()); + + // UUID + String uuid = requestContext.getHeaderString(Constants.X_ECOMP_REQUEST_ID_HEADER); + if (uuid == null) { + // Generate the UUID + uuid = UUID.randomUUID().toString(); + + // Add to MDC for logging + MDC.put("uuid", uuid); + + // This log message should already be with the UUID + uuidGeneration(uuid); + + } else { + // According to Ella, in case this header exists, we don't have to + // perform any validations + // since it's not our responsibilty, so we log the UUID just as it + // was received. + MDC.put("uuid", uuid); + } + return uuid; + } + + private ComponentsUtils getComponentsUtils() { + ServletContext context = this.sr.getSession().getServletContext(); + + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + return webApplicationContext.getBean(ComponentsUtils.class); + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void inHttpRequest() { + if (isInfoLog()) { + log.info("{} {} {}", sr.getMethod(), sr.getRequestURI(), sr.getProtocol()); + } else { + log.debug("{} {} {}", sr.getMethod(), sr.getRequestURI(), sr.getProtocol()); + } + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void outHttpResponse(ContainerResponseContext responseContext) { + if (isInfoLog()) { + log.info("{} {} {} SC=\"{}\"", sr.getMethod(), sr.getRequestURI(), sr.getProtocol(), responseContext.getStatus()); + } else { + log.debug("{} {} {} SC=\"{}\"", sr.getMethod(), sr.getRequestURI(), sr.getProtocol(), responseContext.getStatus()); + } + } + + private boolean isInfoLog() { + boolean logRequest = true; + Configuration configuration = ConfigurationManager.getConfigurationManager().getConfiguration(); + String requestURI = sr.getRequestURI(); + if (requestURI != null && configuration.getUnLoggedUrls() != null) { + logRequest = !configuration.getUnLoggedUrls().contains(requestURI); + } + + return logRequest; + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void uuidGeneration(String uuid) { + log.info("No requestID provided -> Generated UUID {}", uuid); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/ComponentsAvailabilityFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/ComponentsAvailabilityFilter.java new file mode 100644 index 0000000000..c572e2e552 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/ComponentsAvailabilityFilter.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.filters; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Priority; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; + +import org.openecomp.sdc.be.components.impl.HealthCheckBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.api.HealthCheckInfo; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +@Priority(11) +public class ComponentsAvailabilityFilter implements ContainerRequestFilter { + + @Context + protected HttpServletRequest sr; + protected Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private static Logger log = LoggerFactory.getLogger(ComponentsAvailabilityFilter.class.getName()); + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + String requestUrl = requestContext.getUriInfo().getPath(); + if (!requestUrl.equals("healthCheck")) { + List<HealthCheckInfo> beHealthCheckInfos = getBeHealthCheckInfos(this.sr.getSession().getServletContext()); + ActionStatus status = getAggregateBeStatus(beHealthCheckInfos); + + if (!status.equals(ActionStatus.OK)) { + log.error("Components Availability Filter Failed - ES/Cassandra is DOWN"); + availabilityError(requestContext); + } + } + + } + + protected ActionStatus getAggregateBeStatus(List<HealthCheckInfo> beHealthCheckInfos) { + ActionStatus status = ActionStatus.OK; + for (HealthCheckInfo healthCheckInfo : beHealthCheckInfos) { + if (healthCheckInfo.getHealthCheckStatus().equals(HealthCheckStatus.DOWN)) { + status = ActionStatus.GENERAL_ERROR; + break; + } + } + return status; + } + + protected List<HealthCheckInfo> getBeHealthCheckInfos(ServletContext servletContext) { + + List<HealthCheckInfo> healthCheckInfos = new ArrayList<HealthCheckInfo>(); + HealthCheckBusinessLogic healthCheckBusinessLogic = getHealthCheckBL(servletContext); + healthCheckBusinessLogic.getTitanHealthCheck(healthCheckInfos); // Titan + return healthCheckInfos; + } + + protected ComponentsUtils getComponentsUtils() { + ServletContext context = sr.getSession().getServletContext(); + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + ComponentsUtils componentsUtils = webApplicationContext.getBean(ComponentsUtils.class); + return componentsUtils; + } + + protected void availabilityError(ContainerRequestContext requestContext) { + ComponentsUtils componentUtils = getComponentsUtils(); + if (componentUtils == null) { + log.error("Components Availability Filter Failed to get component utils."); + requestContext.abortWith(Response.status(Status.INTERNAL_SERVER_ERROR).build()); + } + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + ResponseBuilder responseBuilder = Response.status(responseFormat.getStatus()); + Response response = responseBuilder.entity(gson.toJson(responseFormat.getRequestError())).build(); + requestContext.abortWith(response); + } + + private HealthCheckBusinessLogic getHealthCheckBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + HealthCheckBusinessLogic healthCheckBl = webApplicationContext.getBean(HealthCheckBusinessLogic.class); + return healthCheckBl; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java new file mode 100644 index 0000000000..9e2abebdc5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java @@ -0,0 +1,1461 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.impl; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; + +import org.codehaus.jackson.Version; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.JsonDeserializer; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.module.SimpleModule; +import org.openecomp.sdc.be.auditing.api.IAuditingManager; +import org.openecomp.sdc.be.components.impl.ResponseFormatManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.graph.datatype.AdditionalInformationEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.AdditionalInfoParameterInfo; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapabilityTypeDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ConsumerDefinition; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GroupTypeDefinition; +import org.openecomp.sdc.be.model.PolicyTypeDefinition; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintJacksonDeserialiser; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.tosca.ToscaError; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.ThreadLocalsHolder; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import fj.data.Either; + +@org.springframework.stereotype.Component("componentUtils") +public class ComponentsUtils { + + @javax.annotation.Resource + private IAuditingManager auditingManager; + + private ResponseFormatManager responseFormatManager; + + private static Logger log = LoggerFactory.getLogger(ComponentsUtils.class.getName()); + + @PostConstruct + public void Init() { + this.responseFormatManager = ResponseFormatManager.getInstance(); + } + + public IAuditingManager getAuditingManager() { + return auditingManager; + } + + public void setAuditingManager(IAuditingManager auditingManager) { + this.auditingManager = auditingManager; + } + + public <T> Either<T, ResponseFormat> convertJsonToObject(String data, User user, Class<T> clazz, AuditingActionEnum actionEnum) { + if (data == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("object is null after converting from json"); + ResponseFormat responseFormat = getInvalidContentErrorAndAudit(user, actionEnum); + return Either.right(responseFormat); + } + try { + T obj = parseJsonToObject(data, clazz); + return Either.left(obj); + } catch (Exception e) { + // INVALID JSON + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("failed to convert from json {}", data, e); + ResponseFormat responseFormat = getInvalidContentErrorAndAudit(user, actionEnum); + return Either.right(responseFormat); + } + } + + public static <T> T parseJsonToObject(String data, Class<T> clazz) { + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create(); + log.trace("convert json to object. json=\n{}", data); + T resource = gson.fromJson(data, clazz); + return resource; + } + + public <T> Either<T, ResponseFormat> convertJsonToObjectUsingObjectMapper(String data, User user, Class<T> clazz, AuditingActionEnum actionEnum, ComponentTypeEnum typeEnum) { + T component = null; + ObjectMapper mapper = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try { + log.trace("convert json to object. json=\n{}", data); + + final SimpleModule module = new SimpleModule("customerSerializationModule", new Version(1, 0, 0, "static version")); + JsonDeserializer<PropertyConstraint> desrializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, desrializer); + // + mapper.registerModule(module); + + component = mapper.readValue(data, clazz); + if (component == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("object is null after converting from json"); + ResponseFormat responseFormat = getInvalidContentErrorAndAuditComponent(user, actionEnum, typeEnum); + return Either.right(responseFormat); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("failed to convert from json {}", data, e); + ResponseFormat responseFormat = getInvalidContentErrorAndAuditComponent(user, actionEnum, typeEnum); + return Either.right(responseFormat); + } + return Either.left(component); + } + + public <T> void addDeserializer(SimpleModule module, Class<T> clazz, final JsonDeserializer<T> deserializer) { + module.addDeserializer(clazz, deserializer); + } + + // Error response + + public ResponseFormat getResponseFormat(ActionStatus actionStatus, String... params) { + return responseFormatManager.getResponseFormat(actionStatus, params); + } + + /** + * Returns the response format of resource error with respective variables according to actionStatus. This is needed for cases where actionStatus is anonymously converted from storage operation, and the caller doesn't know what actionStatus he + * received. It's caller's Responsibility to fill the resource object passed to this function with needed fields. + * + * Note that RESOURCE_IN_USE case passes hardcoded "resource" string to the error parameter. This means that if Resource object will also be used for Service, this code needs to be refactored and we should tell Resource from Service. + * + * @param actionStatus + * @param resource + * @return + */ + public ResponseFormat getResponseFormatByResource(ActionStatus actionStatus, Resource resource) { + if (resource == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case COMPONENT_VERSION_ALREADY_EXIST: + responseFormat = getResponseFormat(ActionStatus.COMPONENT_VERSION_ALREADY_EXIST, ComponentTypeEnum.RESOURCE.getValue(), resource.getVersion()); + break; + case RESOURCE_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resource.getName()); + break; + case COMPONENT_NAME_ALREADY_EXIST: + responseFormat = getResponseFormat(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, ComponentTypeEnum.RESOURCE.getValue(), resource.getName()); + break; + case COMPONENT_IN_USE: + responseFormat = getResponseFormat(ActionStatus.COMPONENT_IN_USE, ComponentTypeEnum.RESOURCE.name().toLowerCase(), resource.getUniqueId()); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + public ResponseFormat getResponseFormatByResource(ActionStatus actionStatus, String resourceName) { + if (resourceName == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case RESOURCE_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceName); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + public ResponseFormat getResponseFormatByCapabilityType(ActionStatus actionStatus, CapabilityTypeDefinition capabilityType) { + if (capabilityType == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case CAPABILITY_TYPE_ALREADY_EXIST: + responseFormat = getResponseFormat(ActionStatus.CAPABILITY_TYPE_ALREADY_EXIST, capabilityType.getType()); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + /** + * Returns the response format of resource error with respective variables according to actionStatus. This is needed for cases where actionStatus is anynomously converted from storage operation, and the caller doesn't know what actionStatus he + * received. It's caller's responisibility to fill the passed resource object with needed fields. + * + * @param actionStatus + * @param user + * @return + */ + public ResponseFormat getResponseFormatByUser(ActionStatus actionStatus, User user) { + if (user == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat requestErrorWrapper; + switch (actionStatus) { + case INVALID_USER_ID: + requestErrorWrapper = getResponseFormat(actionStatus, user.getUserId()); + break; + case INVALID_EMAIL_ADDRESS: + requestErrorWrapper = getResponseFormat(actionStatus, user.getEmail()); + break; + case INVALID_ROLE: + requestErrorWrapper = getResponseFormat(actionStatus, user.getRole()); + break; + case USER_NOT_FOUND: + case USER_ALREADY_EXIST: + case USER_INACTIVE: + case USER_HAS_ACTIVE_ELEMENTS: + requestErrorWrapper = getResponseFormat(actionStatus, user.getUserId()); + break; + default: + requestErrorWrapper = getResponseFormat(actionStatus); + break; + } + return requestErrorWrapper; + } + + public ResponseFormat getResponseFormatByUserId(ActionStatus actionStatus, String userId) { + User user = new User(); + user.setUserId(userId); + return getResponseFormatByUser(actionStatus, user); + } + + public ResponseFormat getResponseFormatByDE(ActionStatus actionStatus, String serviceId, String envName) { + ResponseFormat responseFormat; + + switch (actionStatus) { + case DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE: + responseFormat = getResponseFormat(ActionStatus.DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE, envName); + break; + case DISTRIBUTION_ENVIRONMENT_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.DISTRIBUTION_ENVIRONMENT_NOT_FOUND, envName); + break; + case DISTRIBUTION_ARTIFACT_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.DISTRIBUTION_ARTIFACT_NOT_FOUND, serviceId); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + public ResponseFormat getResponseFormatByArtifactId(ActionStatus actionStatus, String artifactId) { + ResponseFormat responseFormat; + + switch (actionStatus) { + case RESOURCE_NOT_FOUND: + case ARTIFACT_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactId); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + public ResponseFormat getInvalidContentErrorAndAudit(User user, AuditingActionEnum actionEnum) { + ResponseFormat responseFormat = responseFormatManager.getResponseFormat(ActionStatus.INVALID_CONTENT); + log.debug("audit before sending response"); + auditResource(responseFormat, user, null, "", "", actionEnum, null); + return responseFormat; + } + + public ResponseFormat getInvalidContentErrorAndAuditComponent(User user, AuditingActionEnum actionEnum, ComponentTypeEnum typeEnum) { + ResponseFormat responseFormat = responseFormatManager.getResponseFormat(ActionStatus.INVALID_CONTENT); + log.debug("audit before sending response"); + auditComponentAdmin(responseFormat, user, null, "", "", actionEnum, typeEnum); + return responseFormat; + } + + public void auditResource(ResponseFormat responseFormat, User modifier, Resource resource, String prevState, String prevVersion, AuditingActionEnum actionEnum, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + if (actionEnum != null) { + log.trace("Inside auditing for audit action {}", actionEnum.name()); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + + updateUserFields(modifier, auditingFields); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, ComponentTypeEnum.RESOURCE.getValue()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, prevVersion); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, prevState); + if (resource != null) { + // fields that are filled during creation and might still be + // empty + String resourceCurrVersion = (resource.getVersion() != null) ? resource.getVersion() : ""; + String resourceCurrState = (resource.getLifecycleState() != null) ? resource.getLifecycleState().name() : ""; + String uuid = (resource.getUUID() != null) ? resource.getUUID() : ""; + String invariantUUID = (resource.getInvariantUUID() != null) ? resource.getInvariantUUID() : ""; + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resource.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, resourceCurrVersion); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, resourceCurrState); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, invariantUUID); + + } else { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, ""); + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + // In those specific cases we want some specific fields from + // resource object + switch (actionEnum) { + case IMPORT_RESOURCE: + if (resource != null) { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TOSCA_NODE_TYPE, resource.getToscaResourceName()); + } else { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TOSCA_NODE_TYPE, ""); + } + break; + default: + break; + } + + // This is to add/overwrite anything set in this function if some + // params were passed from above, + // for example resourceName of resource import + if (additionalParams != null) { + auditingFields.putAll(additionalParams); + } + + getAuditingManager().auditEvent(auditingFields); + } + } + + private void updateUserFields(User modifier, EnumMap<AuditingFieldsKeysEnum, Object> auditingFields) { + if (modifier != null) { + String firstName = modifier.getFirstName(); + String lastName = modifier.getLastName(); + if (firstName != null || lastName != null) {// to prevent "null + // null" names + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, firstName + " " + lastName); + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId()); + } + } + + public void auditDistributionDownload(ResponseFormat responseFormat, AuditingActionEnum actionEnum, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + log.trace("Inside auditing for audit action {}", actionEnum.name()); + int status = responseFormat.getStatus(); + String message = ""; + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + // This is to add/overwrite anything set in this function if some params + // were passed from above, + // for example resourceName of resource import + if (additionalParams != null) { + auditingFields.putAll(additionalParams); + } + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditExternalGetAsset(ResponseFormat responseFormat, AuditingActionEnum actionEnum, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + log.trace("Inside auditing for audit action {}", actionEnum.name()); + int status = responseFormat.getStatus(); + String message = ""; + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + if (additionalParams != null) { + auditingFields.putAll(additionalParams); + } + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditExternalCrudApiArtifact(ResponseFormat responseFormat, String componentType, String actionEnum, HttpServletRequest request, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + log.trace("Inside auditing for audit action {}", actionEnum); + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + int status = responseFormat.getStatus(); + String message = ""; + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + if (additionalParams != null) { + auditingFields.putAll(additionalParams); + } + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditExternalDownloadArtifact(ResponseFormat responseFormat, String componentType, HttpServletRequest request, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + auditExternalCrudApiArtifact(responseFormat, componentType, AuditingActionEnum.DOWNLOAD_ARTIFACT.getName(), request, additionalParams); + } + + public void auditExternalUploadArtifact(ResponseFormat responseFormat, String componentType, HttpServletRequest request, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, request.getHeader(Constants.USER_ID_HEADER)); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_PREV_ARTIFACT_UUID, ""); + auditExternalCrudApiArtifact(responseFormat, componentType, AuditingActionEnum.ARTIFACT_UPLOAD_BY_API.getName(), request, additionalParams); + } + + public void auditExternalUpdateArtifact(ResponseFormat responseFormat, String componentType, HttpServletRequest request, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, request.getHeader(Constants.USER_ID_HEADER)); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_PREV_ARTIFACT_UUID, ""); + auditExternalCrudApiArtifact(responseFormat, componentType, AuditingActionEnum.ARTIFACT_UPDATE_BY_API.getName(), request, additionalParams); + } + + public void auditExternalDeleteArtifact(ResponseFormat responseFormat, String componentType, HttpServletRequest request, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, request.getHeader(Constants.USER_ID_HEADER)); + additionalParams.put(AuditingFieldsKeysEnum.AUDIT_PREV_ARTIFACT_UUID, ""); + auditExternalCrudApiArtifact(responseFormat, componentType, AuditingActionEnum.ARTIFACT_DELETE_BY_API.getName(), request, additionalParams); + } + + public void auditCategory(ResponseFormat responseFormat, User modifier, String categoryName, String subCategoryName, String groupingName, AuditingActionEnum actionEnum, String componentType) { + log.trace("Inside auditing for audit action {}", actionEnum.name()); + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + updateUserFields(modifier, auditingFields); + // String componentTypeStr = (componentTypeEnum != null ? + // componentTypeEnum.getValue() : null); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_CATEGORY_NAME, categoryName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SUB_CATEGORY_NAME, subCategoryName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_GROUPING_NAME, groupingName); + getAuditingManager().auditEvent(auditingFields); + } + + public ActionStatus convertFromStorageResponse(StorageOperationStatus storageResponse) { + + return convertFromStorageResponse(storageResponse, ComponentTypeEnum.RESOURCE); + } + + public ActionStatus convertFromStorageResponse(StorageOperationStatus storageResponse, ComponentTypeEnum type) { + + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + if (storageResponse == null) { + return responseEnum; + } + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.COMPONENT_NAME_ALREADY_EXIST; + break; + case PARENT_RESOURCE_NOT_FOUND: + responseEnum = ActionStatus.PARENT_RESOURCE_NOT_FOUND; + break; + case MULTIPLE_PARENT_RESOURCE_FOUND: + responseEnum = ActionStatus.MULTIPLE_PARENT_RESOURCE_FOUND; + break; + case NOT_FOUND: + if (ComponentTypeEnum.RESOURCE == type) { + responseEnum = ActionStatus.RESOURCE_NOT_FOUND; + } else if (ComponentTypeEnum.PRODUCT == type) { + responseEnum = ActionStatus.PRODUCT_NOT_FOUND; + } else { + responseEnum = ActionStatus.SERVICE_NOT_FOUND; + } + break; + case FAILED_TO_LOCK_ELEMENT: + responseEnum = ActionStatus.COMPONENT_IN_USE; + break; + case ARTIFACT_NOT_FOUND: + responseEnum = ActionStatus.ARTIFACT_NOT_FOUND; + break; + case DISTR_ENVIRONMENT_NOT_AVAILABLE: + responseEnum = ActionStatus.DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE; + break; + case DISTR_ENVIRONMENT_NOT_FOUND: + responseEnum = ActionStatus.DISTRIBUTION_ENVIRONMENT_NOT_FOUND; + break; + case DISTR_ENVIRONMENT_SENT_IS_INVALID: + responseEnum = ActionStatus.DISTRIBUTION_ENVIRONMENT_INVALID; + break; + case DISTR_ARTIFACT_NOT_FOUND: + responseEnum = ActionStatus.DISTRIBUTION_ARTIFACT_NOT_FOUND; + break; + case INVALID_TYPE: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case INVALID_VALUE: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case CSAR_NOT_FOUND: + responseEnum = ActionStatus.CSAR_NOT_FOUND; + break; + case PROPERTY_NAME_ALREADY_EXISTS: + responseEnum = ActionStatus.PROPERTY_NAME_ALREADY_EXISTS; + break; + case MATCH_NOT_FOUND: + responseEnum = ActionStatus.COMPONENT_SUB_CATEGORY_NOT_FOUND_FOR_CATEGORY; + break; + case CATEGORY_NOT_FOUND: + responseEnum = ActionStatus.COMPONENT_CATEGORY_NOT_FOUND; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ActionStatus convertFromToscaError(ToscaError toscaError) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + if (toscaError == null) { + return responseEnum; + } + switch (toscaError) {// TODO match errors + case NODE_TYPE_CAPABILITY_ERROR: + case NOT_SUPPORTED_TOSCA_TYPE: + case NODE_TYPE_REQUIREMENT_ERROR: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + return responseEnum; + } + + public ActionStatus convertFromStorageResponseForCapabilityType(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.CAPABILITY_TYPE_ALREADY_EXIST; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.CAPABILITY_TYPE_ALREADY_EXIST; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ActionStatus convertFromStorageResponseForLifecycleType(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.LIFECYCLE_TYPE_ALREADY_EXIST; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.LIFECYCLE_TYPE_ALREADY_EXIST; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ActionStatus convertFromStorageResponseForResourceInstance(StorageOperationStatus storageResponse, boolean isRelation) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case INVALID_ID: + responseEnum = ActionStatus.RESOURCE_INSTANCE_BAD_REQUEST; + break; + case INVALID_PROPERTY: + responseEnum = ActionStatus.INVALID_PROPERTY; + break; + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case MATCH_NOT_FOUND: + responseEnum = ActionStatus.RESOURCE_INSTANCE_MATCH_NOT_FOUND; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.RESOURCE_INSTANCE_ALREADY_EXIST; + break; + case NOT_FOUND: + if (isRelation) { + responseEnum = ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND; + } else { + responseEnum = ActionStatus.RESOURCE_INSTANCE_NOT_FOUND; + } + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ResponseFormat getResponseFormatForResourceInstance(ActionStatus actionStatus, String serviceName, String resourceInstanceName) { + ResponseFormat responseFormat; + + switch (actionStatus) { + case RESOURCE_INSTANCE_NOT_FOUND: + responseFormat = getResponseFormat(actionStatus, resourceInstanceName); + break; + default: + responseFormat = getResponseFormat(actionStatus, serviceName); + break; + } + return responseFormat; + } + + public ResponseFormat getResponseFormatForResourceInstanceProperty(ActionStatus actionStatus, String resourceInstanceName) { + ResponseFormat responseFormat; + + switch (actionStatus) { + case RESOURCE_INSTANCE_NOT_FOUND: + responseFormat = getResponseFormat(actionStatus, resourceInstanceName); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + public ActionStatus convertFromStorageResponseForResourceInstanceProperty(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case INVALID_ID: + responseEnum = ActionStatus.RESOURCE_INSTANCE_BAD_REQUEST; + break; + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case MATCH_NOT_FOUND: + responseEnum = ActionStatus.RESOURCE_INSTANCE_MATCH_NOT_FOUND; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.RESOURCE_INSTANCE_ALREADY_EXIST; + break; + case NOT_FOUND: + responseEnum = ActionStatus.RESOURCE_INSTANCE_NOT_FOUND; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public void auditComponentAdmin(ResponseFormat responseFormat, User modifier, Component component, String prevState, String prevVersion, AuditingActionEnum actionEnum, ComponentTypeEnum type) { + auditComponent(responseFormat, modifier, component, prevState, prevVersion, actionEnum, type, null); + } + + public void auditComponent(ResponseFormat responseFormat, User modifier, Component component, String prevState, String prevVersion, AuditingActionEnum actionEnum, ComponentTypeEnum type, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) { + if (actionEnum != null) { + log.trace("Inside auditing for audit action {}", actionEnum.name()); + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + + updateUserFields(modifier, auditingFields); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, type.getValue().replace(" ", "")); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, prevVersion); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, prevState); + if (component != null) { + // fields that are filled during creation and might still be + // empty + String resourceCurrVersion = component.getVersion(); + String resourceCurrState = (component.getLifecycleState() != null) ? component.getLifecycleState().name() : ""; + String resourceUuid = (component.getUUID() != null) ? component.getUUID() : ""; + String invariantUUID = (component.getInvariantUUID() != null) ? component.getInvariantUUID() : ""; + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, resourceCurrVersion); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, resourceCurrState); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, resourceUuid); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, invariantUUID); + } else { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, ""); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, ""); + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + // This is meant to overwrite anything set in this function if some + // params were passed from above, + // for example resourceName of resource import + if (additionalParams != null) { + auditingFields.putAll(additionalParams); + } + + getAuditingManager().auditEvent(auditingFields); + } + } + + public void auditDistributionEngine(AuditingActionEnum actionEnum, String environmentName, String topicName, String role, String apiKey, String status) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, environmentName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, topicName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ROLE, role); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_API_KEY, apiKey); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditDistributionNotification(AuditingActionEnum actionEnum, String serviceUUID, String resourceName, String resourceType, String currVersion, String modifierUid, String modifierName, String environmentName, String currState, + String topicName, String distributionId, String description, String status) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, serviceUUID); + + // auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, + // environmentName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, topicName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, distributionId); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, currVersion); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, currState); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, resourceType); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, description); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifierUid); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifierName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceName); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditAuthEvent(AuditingActionEnum actionEnum, String url, String user, String authStatus, String realm) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_AUTH_URL, url); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_AUTH_USER, user); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_AUTH_STATUS, authStatus); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_AUTH_REALM, realm); + getAuditingManager().auditEvent(auditingFields); + } + + public void auditDistributionStatusNotification(AuditingActionEnum actionEnum, String distributionId, String consumerId, String topicName, String resourceUrl, String statusTime, String status, String errorReason) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_REQUEST_ID, distributionId); + ThreadLocalsHolder.setUuid(distributionId); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, distributionId); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, consumerId); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, topicName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, resourceUrl); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TIME, statusTime); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, errorReason); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditGetUebCluster(AuditingActionEnum actionEnum, String consumerId, String statusTime, String status, String description) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, consumerId); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TIME, statusTime); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_DESC, description); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditMissingInstanceId(AuditingActionEnum actionEnum, String status, String description) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, null); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_TIMESTAMP, null); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, description); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditTopicACLKeys(AuditingActionEnum actionEnum, String envName, String topicName, String role, String apiPublicKey, String status) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, envName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_TOPIC_NAME, topicName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ROLE, role); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_API_KEY, apiPublicKey); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditRegisterOrUnRegisterEvent(AuditingActionEnum actionEnum, String consumerId, String apiPublicKey, String envName, String status, String statusDesc, String notifTopicName, String statusTopicName) { + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, consumerId); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_API_KEY, apiPublicKey); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ENVRIONMENT_NAME, envName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_DESC, statusDesc); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_NOTIFICATION_TOPIC_NAME, notifTopicName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TOPIC_NAME, statusTopicName); + getAuditingManager().auditEvent(auditingFields); + } + + public void auditServiceDistributionDeployed(AuditingActionEnum actionEnum, String serviceName, String serviceVersion, String serviceUUID, String distributionId, String status, String desc, User modifier) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, serviceUUID); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFirstName() + " " + modifier.getLastName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, "Service"); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, serviceName); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, serviceVersion); + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, distributionId); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, desc); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditConsumerCredentialsEvent(AuditingActionEnum actionEnum, ConsumerDefinition consumer, ResponseFormat responseFormat, User modifier) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + if (modifier != null) { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFirstName() + " " + modifier.getLastName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId()); + } + StringBuilder ecompUser = new StringBuilder(); + if (consumer != null) { + if (consumer.getConsumerName() != null && !consumer.getConsumerName().trim().isEmpty()) { + ecompUser.append(consumer.getConsumerName()); + } + if (consumer.getConsumerSalt() != null && !consumer.getConsumerSalt().trim().isEmpty()) { + if (ecompUser.length() > 0) { + ecompUser.append(","); + } + ecompUser.append(consumer.getConsumerSalt()); + } + if (consumer.getConsumerPassword() != null && !consumer.getConsumerPassword().trim().isEmpty()) { + if (ecompUser.length() > 0) { + ecompUser.append(","); + } + ecompUser.append(consumer.getConsumerPassword()); + } + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ECOMP_USER, ecompUser.toString()); + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + + getAuditingManager().auditEvent(auditingFields); + } + + public void auditGetUsersList(AuditingActionEnum actionEnum, User modifier, String details, ResponseFormat responseFormat) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + if (modifier != null) { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFirstName() + " " + modifier.getLastName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId()); + } + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_DETAILS, details); + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + getAuditingManager().auditEvent(auditingFields); + } + + public void auditAdminUserAction(AuditingActionEnum actionEnum, User modifier, User userBefore, User userAfter, ResponseFormat responseFormat) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + if (modifier != null) { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFirstName() + " " + modifier.getLastName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId()); + } else { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, ""); + } + if (userBefore != null) { + String userBeforeUserId = (userBefore.getUserId() != null) ? userBefore.getUserId() : ""; + String userBeforFirstName = (userBefore.getFirstName() != null) ? ", " + userBefore.getFirstName() + " " : ""; + String userBeforLastName = (userBefore.getLastName() != null) ? userBefore.getLastName() : ""; + String userBeforEmail = (userBefore.getEmail() != null) ? ", " + userBefore.getEmail() : ""; + String userBeforRloe = (userBefore.getRole() != null) ? ", " + userBefore.getRole() : ""; + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_BEFORE, userBeforeUserId + userBeforFirstName + userBeforLastName + userBeforEmail + userBeforRloe); + } else { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_BEFORE, ""); + } + if (userAfter != null) { + String userAfterUserId = (userAfter.getUserId() != null) ? userAfter.getUserId() : ""; + String userAfterFirstName = (userAfter.getFirstName() != null) ? ", " + userAfter.getFirstName() + " " : ""; + String userAfterLastName = (userAfter.getLastName() != null) ? userAfter.getLastName() : ""; + String userAfterEmail = (userAfter.getEmail() != null) ? ", " + userAfter.getEmail() : ""; + String userAfterRloe = (userAfter.getRole() != null) ? ", " + userAfter.getRole() : ""; + + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_AFTER, userAfterUserId + userAfterFirstName + userAfterLastName + userAfterEmail + userAfterRloe); + } else { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_AFTER, ""); + } + + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + getAuditingManager().auditEvent(auditingFields); + } + + public void auditUserAccess(AuditingActionEnum actionEnum, User user, ResponseFormat responseFormat) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_USER_UID, user.getFirstName() + " " + user.getLastName() + '(' + user.getUserId() + ')'); + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + getAuditingManager().auditEvent(auditingFields); + } + + public void auditGetCategoryHierarchy(AuditingActionEnum actionEnum, User modifier, String details, ResponseFormat responseFormat) { + + EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, actionEnum.getName()); + if (modifier != null) { + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFirstName() + " " + modifier.getLastName()); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId()); + } + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DETAILS, details); + int status = responseFormat.getStatus(); + String message = ""; + + if (responseFormat.getMessageId() != null) { + message = responseFormat.getMessageId() + ": "; + } + message += responseFormat.getFormattedMessage(); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, status); + auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message); + getAuditingManager().auditEvent(auditingFields); + } + + public ResponseFormat getResponseFormatByComponent(ActionStatus actionStatus, Component component, ComponentTypeEnum type) { + if (component == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case COMPONENT_VERSION_ALREADY_EXIST: + responseFormat = getResponseFormat(ActionStatus.COMPONENT_VERSION_ALREADY_EXIST, type.getValue(), component.getVersion()); + break; + case RESOURCE_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + break; + case COMPONENT_NAME_ALREADY_EXIST: + responseFormat = getResponseFormat(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, type.getValue(), component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + break; + case COMPONENT_IN_USE: + responseFormat = getResponseFormat(ActionStatus.COMPONENT_IN_USE, type.name().toLowerCase(), component.getUniqueId()); + break; + case SERVICE_DEPLOYMENT_ARTIFACT_NOT_FOUND: + responseFormat = getResponseFormat(ActionStatus.SERVICE_DEPLOYMENT_ARTIFACT_NOT_FOUND, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } + + public Either<Boolean, ResponseFormat> validateStringNotEmpty(User user, Component component, String value, ActionStatus badResult, AuditingActionEnum actionEnum) { + if ((value == null) || (value.trim().isEmpty())) { + log.info(badResult.name()); + ResponseFormat errorResponse = getResponseFormat(badResult); + if (actionEnum != null) { + log.debug("audit before sending response"); + auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, getComponentType(component)); + } + return Either.right(errorResponse); + } + return Either.left(true); + } + + public Boolean validateStringNotEmpty(String value) { + if ((value == null) || (value.trim().isEmpty())) { + return false; + } + return true; + } + + private ComponentTypeEnum getComponentType(Component component) { + if (component instanceof Service) { + return ComponentTypeEnum.SERVICE; + } // else if(component instanceof Resource){ + return null; + } + + public Either<Boolean, ResponseFormat> validateStringMatchesPattern(User user, Component component, String value, Pattern pattern, ActionStatus badResult, AuditingActionEnum actionEnum) { + if (!pattern.matcher(value).matches()) { + log.error(badResult.name()); + ResponseFormat errorResponse = getResponseFormat(badResult); + if (actionEnum != null) { + log.debug("audit before sending response"); + auditComponentAdmin(errorResponse, user, component, "", "", actionEnum, getComponentType(component)); + } + return Either.right(errorResponse); + } + return Either.left(true); + } + + /** + * + * " Error: Missing Mandatory Informational %s1 %s2 : %s3 " where %s1 - "resource"/"service" %s2 - "artifact"/ "artifacts" %s3 - Comma separated list of missing informational artifact types + * + * @param resource + * @param componentMissingMandatoryArtifacts + * @param value + * @return + */ + public ResponseFormat getResponseFormatByMissingArtifacts(ComponentTypeEnum componentType, Map<String, ArtifactDefinition> artifacts) { + + String artifactTitle = "artifact"; + if (artifacts.size() > 1) { + artifactTitle = "artifacts"; + } + Collection<ArtifactDefinition> artifactsLabels = artifacts.values(); + StringBuilder artifactsLabelBuilder = new StringBuilder(); + + List<ArtifactDefinition> artifactsLabelsList = new ArrayList<ArtifactDefinition>(); + artifactsLabelsList.addAll(artifactsLabels); + for (int i = 0; i < artifactsLabelsList.size(); i++) { + ArtifactDefinition artifactDef = artifactsLabelsList.get(i); + artifactsLabelBuilder.append(artifactDef.getArtifactDisplayName()); + if (i < artifactsLabelsList.size() - 1) { + artifactsLabelBuilder.append(";"); + } + } + ResponseFormat responseFormat = getResponseFormat(ActionStatus.COMPONENT_MISSING_MANDATORY_ARTIFACTS, componentType.name().toLowerCase(), artifactTitle, artifactsLabelBuilder.toString()); + + return responseFormat; + } + + public ActionStatus convertFromStorageResponseForAdditionalInformation(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.COMPONENT_NAME_ALREADY_EXIST; + break; + case INVALID_ID: + responseEnum = ActionStatus.ADDITIONAL_INFORMATION_NOT_FOUND; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ResponseFormat getResponseFormatAdditionalProperty(ActionStatus actionStatus, AdditionalInfoParameterInfo additionalInfoParameterInfo, NodeTypeEnum nodeType, AdditionalInformationEnum labelOrValue) { + + if (additionalInfoParameterInfo == null) { + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(); + } + if (labelOrValue == null) { + labelOrValue = AdditionalInformationEnum.None; + } + + ResponseFormat responseFormat = null; + switch (actionStatus) { + case COMPONENT_NAME_ALREADY_EXIST: + responseFormat = getResponseFormat(actionStatus, "Additional parameter", additionalInfoParameterInfo.getKey()); + break; + case ADDITIONAL_INFORMATION_EXCEEDS_LIMIT: + responseFormat = getResponseFormat(actionStatus, labelOrValue.name().toLowerCase(), ValidationUtils.ADDITIONAL_INFORMATION_KEY_MAX_LENGTH.toString()); + break; + case ADDITIONAL_INFORMATION_MAX_NUMBER_REACHED: + responseFormat = getResponseFormat(actionStatus, nodeType.name().toLowerCase()); + break; + case ADDITIONAL_INFORMATION_EMPTY_STRING_NOT_ALLOWED: + responseFormat = getResponseFormat(actionStatus); + break; + case ADDITIONAL_INFORMATION_KEY_NOT_ALLOWED_CHARACTERS: + responseFormat = getResponseFormat(actionStatus); + break; + case ADDITIONAL_INFORMATION_VALUE_NOT_ALLOWED_CHARACTERS: + responseFormat = getResponseFormat(actionStatus); + break; + case ADDITIONAL_INFORMATION_NOT_FOUND: + responseFormat = getResponseFormat(actionStatus); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + + return responseFormat; + } + + public ResponseFormat getResponseFormatAdditionalProperty(ActionStatus actionStatus) { + return getResponseFormatAdditionalProperty(actionStatus, null, null, null); + } + + public ActionStatus convertFromStorageResponseForConsumer(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.CONSUMER_ALREADY_EXISTS; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.CONSUMER_ALREADY_EXISTS; + break; + case NOT_FOUND: + responseEnum = ActionStatus.ECOMP_USER_NOT_FOUND; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ActionStatus convertFromStorageResponseForGroupType(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.GROUP_TYPE_ALREADY_EXIST; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.GROUP_TYPE_ALREADY_EXIST; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ActionStatus convertFromStorageResponseForDataType(StorageOperationStatus storageResponse) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.DATA_TYPE_ALREADY_EXIST; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.DATA_TYPE_ALREADY_EXIST; + break; + case CANNOT_UPDATE_EXISTING_ENTITY: + responseEnum = ActionStatus.DATA_TYPE_CANNOT_BE_UPDATED_BAD_REQUEST; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); + return responseEnum; + } + + public ResponseFormat getResponseFormatByGroupType(ActionStatus actionStatus, GroupTypeDefinition groupType) { + if (groupType == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case GROUP_MEMBER_EMPTY: + case GROUP_TYPE_ALREADY_EXIST: + responseFormat = getResponseFormat(actionStatus, groupType.getType()); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + + } + + public ResponseFormat getResponseFormatByPolicyType(ActionStatus actionStatus, PolicyTypeDefinition policyType) { + if (policyType == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case POLICY_TYPE_ALREADY_EXIST: + responseFormat = getResponseFormat(actionStatus, policyType.getType()); + break; + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + + } + + public ResponseFormat getResponseFormatByDataType(ActionStatus actionStatus, DataTypeDefinition dataType, List<String> properties) { + if (dataType == null) { + return getResponseFormat(actionStatus); + } + ResponseFormat responseFormat; + + switch (actionStatus) { + case DATA_TYPE_ALREADY_EXIST: + responseFormat = getResponseFormat(actionStatus, dataType.getName()); + break; + case DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM: + responseFormat = getResponseFormat(actionStatus, dataType.getName()); + break; + case DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY: + responseFormat = getResponseFormat(actionStatus, dataType.getName()); + break; + case DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR: + responseFormat = getResponseFormat(actionStatus, dataType.getName(), properties == null ? "" : String.valueOf(properties)); + break; + case DATA_TYPE_DERIVED_IS_MISSING: + responseFormat = getResponseFormat(actionStatus, dataType.getDerivedFromName()); + break; + case DATA_TYPE_DUPLICATE_PROPERTY: + responseFormat = getResponseFormat(actionStatus, dataType.getName()); + break; + case DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE: + responseFormat = getResponseFormat(actionStatus, dataType.getName(), properties == null ? "" : String.valueOf(properties)); + break; + case DATA_TYPE_CANNOT_HAVE_PROPERTIES: + responseFormat = getResponseFormat(actionStatus, dataType.getName()); + break; + case DATA_TYPE_CANNOT_BE_UPDATED_BAD_REQUEST: + responseFormat = getResponseFormat(actionStatus, dataType.getName()); + break; + + default: + responseFormat = getResponseFormat(actionStatus); + break; + } + return responseFormat; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/DownloadArtifactLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/DownloadArtifactLogic.java new file mode 100644 index 0000000000..fff6fd15a4 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/DownloadArtifactLogic.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.impl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpStatus; +import org.eclipse.jgit.util.Base64; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ResourceUploadStatus; +import org.openecomp.sdc.be.info.ArtifactAccessInfo; +import org.openecomp.sdc.be.info.ArtifactAccessList; +import org.openecomp.sdc.be.info.ServletJsonResponse; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import fj.data.Either; + +public class DownloadArtifactLogic { + + private static Logger log = LoggerFactory.getLogger(DownloadArtifactLogic.class.getName()); + + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + public Response downloadArtifact(final String resourceName, final String resourceVersion, final String artifactName, Either<? extends ESArtifactData, ResourceUploadStatus> getArtifactStatus, String artifactId) { + Response response = null; + + if (getArtifactStatus.isRight()) { + log.debug("Could not find artifact for with id: {}", artifactId); + ResourceUploadStatus status = getArtifactStatus.right().value(); + if (status == status.COMPONENT_NOT_EXIST) + response = Response.status(HttpStatus.SC_NO_CONTENT).build(); + else + response = Response.status(HttpStatus.SC_NOT_FOUND).build(); + + return response; + } + // convert artifact to inputstream + else { + ESArtifactData artifactData = getArtifactStatus.left().value(); + byte[] artifactPayload = artifactData.getDataAsArray(); + + String payloadStr = new String(artifactPayload); + byte[] decodedPayload = artifactPayload; + boolean isEncoded = GeneralUtility.isBase64Encoded(payloadStr); + if (isEncoded) { + log.debug("payload is encoded. perform decode"); + decodedPayload = Base64.decode(new String(artifactPayload)); + } + final InputStream artifactStream = new ByteArrayInputStream(decodedPayload); + log.debug("found artifact for with id: {}", artifactId); + try { + + // outputstream for response + StreamingOutput stream = new StreamingOutput() { + public void write(OutputStream output) throws IOException, WebApplicationException { + try { + IOUtils.copy(artifactStream, output); + } catch (Exception e) { + throw new WebApplicationException(e); + } + } + }; + artifactStream.close(); + return Response.ok(stream).type(MediaType.APPLICATION_OCTET_STREAM_TYPE).header("content-disposition", "attachment; filename = " + artifactName) + // .header(Constants.MD5_HEADER, new + // String(artifactData.getArtifactChecksum())) + .build(); + + } catch (IOException e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Failed to stream artifact data on the response"); + BeEcompErrorManager.getInstance().logBeSystemError("Failed to stream artifact data on the response"); + log.debug("Failed to stream artifact data on the response: {}", e.getMessage()); + response = buildResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Failed to stream artifact data on the response"); + return response; + } + } + } + + public List<ArtifactAccessInfo> convertArtifactList(List<? extends ESArtifactData> artifactsList, String servletPath) { + + List<ArtifactAccessInfo> artifactAccessList = new ArrayList<ArtifactAccessInfo>(); + for (ESArtifactData artifact : artifactsList) { + ArtifactAccessInfo accessInfo = new ArtifactAccessInfo(artifact, servletPath); + artifactAccessList.add(accessInfo); + } + return artifactAccessList; + } + + public Response createArtifactListResponse(final String serviceName, Either<List<ESArtifactData>, ResourceUploadStatus> getArtifactsStatus/* + * List < ? extends IResourceData> artifactsList + */, String servletPath) { + Response response; + List<ArtifactAccessInfo> artifactAccessInfos; + if (getArtifactsStatus.isRight()) { + // if there are no artifacts - return No-Content + ResourceUploadStatus status = getArtifactsStatus.right().value(); + if (status == ResourceUploadStatus.COMPONENT_NOT_EXIST || status == ResourceUploadStatus.SERVICE_NOT_EXIST) { + log.debug("resource {} does not exist", serviceName); + response = Response.status(HttpStatus.SC_NOT_FOUND).entity("[]").build(); + + } else { + log.debug("No content was found for {}", serviceName); + response = Response.status(HttpStatus.SC_NO_CONTENT).entity("[]").build(); + } + return response; + } else { + List<? extends ESArtifactData> artifactsList = getArtifactsStatus.left().value(); + log.debug("{} artifacts were found for {}", artifactsList.size(), serviceName); + artifactAccessInfos = convertArtifactList(artifactsList, servletPath); + + String artifactDataJson = gson.toJson(new ArtifactAccessList(artifactAccessInfos)); + response = Response.status(HttpStatus.SC_OK).entity(artifactDataJson).type(MediaType.APPLICATION_JSON_TYPE).build(); + + return response; + } + } + + public Response buildResponse(int status, String errorMessage) { + + ServletJsonResponse jsonResponse = new ServletJsonResponse(); + jsonResponse.setDescription(errorMessage); + jsonResponse.setSource(Constants.CATALOG_BE); + + Response response = Response.status(status).entity(jsonResponse).build(); + + return response; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ServletUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ServletUtils.java new file mode 100644 index 0000000000..3a5d9bf85f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ServletUtils.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.impl; + +import javax.annotation.Resource; + +import org.openecomp.sdc.be.user.IUserBusinessLogic; +import org.springframework.stereotype.Component; + +import com.google.gson.Gson; + +@Component("servletUtils") +public class ServletUtils { + @Resource + private ComponentsUtils componentsUtils; + private Gson gson = new Gson(); + @Resource + private IUserBusinessLogic adminManager; + + public ComponentsUtils getComponentsUtils() { + return componentsUtils; + } + + public Gson getGson() { + return gson; + } + + public IUserBusinessLogic getUserAdmin() { + return adminManager; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/WebAppContextWrapper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/WebAppContextWrapper.java new file mode 100644 index 0000000000..cb21984a7f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/WebAppContextWrapper.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.impl; + +import javax.servlet.ServletContext; + +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +public class WebAppContextWrapper { + + public WebApplicationContext getWebAppContext(ServletContext context) { + + return WebApplicationContextUtils.getWebApplicationContext(context); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactAccessInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactAccessInfo.java new file mode 100644 index 0000000000..deb446e32f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactAccessInfo.java @@ -0,0 +1,159 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import org.openecomp.sdc.be.resources.data.ESArtifactData; + +public class ArtifactAccessInfo { + + public ArtifactAccessInfo() { + } + + public ArtifactAccessInfo(ESArtifactData artifactData) { + // this.name = artifactData.getArtifactName(); + this.id = artifactData.getId(); + // this.type = artifactData.getArtifactType(); + // this.description = artifactData.getArtifactDescription(); + // this.creator = artifactData.getArtifactCreator(); + // DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL); + // Date creationTimestamp = artifactData.getArtifactCreationTimestamp(); + // this.creationTime = (creationTimestamp != + // null)?dateFormat.format(creationTimestamp): null; + // Date updateTimestamp = artifactData.getArtifactLastUpdateTimestamp(); + // this.lastUpdateTime = (updateTimestamp != + // null)?dateFormat.format(updateTimestamp):null; + // this.lastUpdater = artifactData.getArtifactLastUpdater(); + // if (artifactData.getArtifactChecksum() != null){ + // this.checksum = new String(artifactData.getArtifactChecksum()); + // } else { + // this.checksum = null; + // } + } + + public ArtifactAccessInfo(ESArtifactData artifactData, String servletContext) { + // this.name = artifactData.getArtifactName(); + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder = urlBuilder.append(servletContext).append("/"); + // if (ArtifactDataEnum.COMPONENT_ARTIFACT.equals(resource)){ + urlBuilder.append("resources/") + // .append(artifactData.getResourceId()).append("/") + + .append("/artifacts/"); + /* + * }else { ServiceArtifactData serviceArtifact = (ServiceArtifactData)artifactData; urlBuilder.append("services/") .append(serviceArtifact.getServiceName()).append("/") .append(serviceArtifact.getServiceVersion()) .append("/artifacts/") + * .append(serviceArtifact.getNodeTemplateName()) .append("/"); } + */ + // urlBuilder.append(artifactData.getArtifactName()); + this.url = urlBuilder.toString(); + + } + + private String name; + private String url; + private String id; + private String type; + private String description; + private String creator; + private String creationTime; + private String lastUpdater; + private String lastUpdateTime; + private String checksum; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getCreationTime() { + return creationTime; + } + + public void setCreationTime(String creationTime) { + this.creationTime = creationTime; + } + + public String getLastUpdater() { + return lastUpdater; + } + + public void setLastUpdater(String lastUpdater) { + this.lastUpdater = lastUpdater; + } + + public String getLastUpdateTime() { + return lastUpdateTime; + } + + public void setLastUpdateTime(String lastUpdateTime) { + this.lastUpdateTime = lastUpdateTime; + } + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactAccessList.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactAccessList.java new file mode 100644 index 0000000000..ddeb0505d9 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactAccessList.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class ArtifactAccessList { + + public ArtifactAccessList(List<ArtifactAccessInfo> artifacts) { + this.artifacts = artifacts; + } + + private List<ArtifactAccessInfo> artifacts; + + public List<ArtifactAccessInfo> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<ArtifactAccessInfo> artifacts) { + this.artifacts = artifacts; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactDefinitionInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactDefinitionInfo.java new file mode 100644 index 0000000000..163d220871 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactDefinitionInfo.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; + +public class ArtifactDefinitionInfo { + + private String uniqueId; + /** Specifies the display name of the artifact. */ + private String artifactName; + private String artifactDisplayName; + private String artifactVersion; + private String artifactUUID; + + public ArtifactDefinitionInfo(ArtifactDefinition artifactDefinition) { + uniqueId = artifactDefinition.getUniqueId(); + artifactName = artifactDefinition.getArtifactName(); + artifactDisplayName = artifactDefinition.getArtifactDisplayName(); + artifactVersion = artifactDefinition.getArtifactVersion(); + artifactUUID = artifactDefinition.getArtifactUUID(); + + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + + public String getArtifactDisplayName() { + return artifactDisplayName; + } + + public void setArtifactDisplayName(String artifactDisplayName) { + this.artifactDisplayName = artifactDisplayName; + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public String getArtifactUUID() { + return artifactUUID; + } + + public void setArtifactUUID(String artifactUUID) { + this.artifactUUID = artifactUUID; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactTemplateInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactTemplateInfo.java new file mode 100644 index 0000000000..fca7bf38d8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactTemplateInfo.java @@ -0,0 +1,352 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.Configuration.DeploymentArtifactTypeConfig; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactType; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import fj.data.Either; + +public class ArtifactTemplateInfo { + public static final String TYPE = "type"; + public static final String FILE_NAME = "fileName"; + public static final String ENV = "env"; + public static final String IS_BASE = "isBase"; + + private static final String CSAR_HEAT = "HEAT"; + private static final String CSAR_ARTIFACT = "artifacts"; + private static final String CSAR_NETWORK = "network"; + private static final String CSAR_VOLUME = "volume"; + private static final String CSAR_NESTED = "nested"; + private static final Object DESC = "description"; + private static Logger log = LoggerFactory.getLogger(ArtifactTemplateInfo.class.getName()); + String type; + String fileName; + String env; + boolean isBase; + String groupName; + String description; + + List<ArtifactTemplateInfo> relatedArtifactsInfo; + private static Gson gson = new Gson(); + + public ArtifactTemplateInfo() { + super(); + } + + public ArtifactTemplateInfo(String type, String fileName, String env, List<ArtifactTemplateInfo> relatedArtifactsInfo) { + super(); + this.type = type; + this.fileName = fileName; + this.env = env; + this.relatedArtifactsInfo = relatedArtifactsInfo; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public List<ArtifactTemplateInfo> getRelatedArtifactsInfo() { + return relatedArtifactsInfo; + } + + public void setRelatedArtifactsInfo(List<ArtifactTemplateInfo> relatedArtifactsInfo) { + this.relatedArtifactsInfo = relatedArtifactsInfo; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public boolean isBase() { + return isBase; + } + + public void setBase(boolean isBase) { + this.isBase = isBase; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "ArtifactTemplateInfo [type=" + type + ", fileName=" + fileName + ", env=" + env + ", isBase=" + isBase + ", groupName=" + groupName + ", description=" + description + ", relatedArtifactsInfo=" + relatedArtifactsInfo + "]"; + } + + public static Either<ArtifactTemplateInfo, ResponseFormat> createArtifactTemplateInfoFromJson(ComponentsUtils componentsUtils, String type, Map<String, Object> o, List<ArtifactTemplateInfo> createdArtifactTemplateInfoList, + ArtifactTemplateInfo parentArtifact) { + String content = gson.toJson(o); + JsonObject jsonElement = new JsonObject(); + ArtifactTemplateInfo resourceInfo = new ArtifactTemplateInfo(); + + jsonElement = gson.fromJson(content, jsonElement.getClass()); + + Map<String, Object> artifactTemplateMap = componentsUtils.parseJsonToObject(jsonElement.toString(), HashMap.class); + if (artifactTemplateMap.containsKey(TYPE)) + resourceInfo.setType((String) artifactTemplateMap.get(TYPE)); + if (artifactTemplateMap.containsKey(FILE_NAME)) + resourceInfo.setFileName((String) artifactTemplateMap.get(FILE_NAME)); + if (artifactTemplateMap.containsKey(IS_BASE)) + resourceInfo.setBase((Boolean) artifactTemplateMap.get(IS_BASE)); + if (artifactTemplateMap.containsKey(ENV)) { + Object envObj = artifactTemplateMap.get(ENV); + String envStr = ""; + if (envObj instanceof String) { + envStr = (String) envObj; + } else if (envObj instanceof Map) { + Map envMap = (Map) envObj; + if (envMap.containsKey(FILE_NAME)) { + envStr = (String) envMap.get(FILE_NAME); + } + } + resourceInfo.setEnv(envStr); + } + if (artifactTemplateMap.containsKey(DESC)) { + resourceInfo.setDescription((String) artifactTemplateMap.get(DESC)); + } else { + resourceInfo.setDescription((String) artifactTemplateMap.get(FILE_NAME)); + } + + boolean artifactTypeExist = false; + String correctType = type; + if (type.equalsIgnoreCase(CSAR_NESTED)) + correctType = ArtifactTypeEnum.HEAT_NESTED.getType(); + else if ((type.equalsIgnoreCase(CSAR_VOLUME))) + correctType = ArtifactTypeEnum.HEAT_VOL.getType(); + else if ((type.equalsIgnoreCase(CSAR_NETWORK))) + correctType = ArtifactTypeEnum.HEAT_NET.getType(); + else if ((type.equalsIgnoreCase(CSAR_ARTIFACT))) + correctType = ArtifactTypeEnum.HEAT_ARTIFACT.getType(); + else if ((type.equalsIgnoreCase(CSAR_HEAT))) + correctType = ArtifactTypeEnum.HEAT.getType(); + else + correctType = ArtifactTypeEnum.OTHER.getType(); + Either<List<ArtifactType>, ActionStatus> allArtifactTypes = getDeploymentArtifactTypes(NodeTypeEnum.Resource); + + if (allArtifactTypes.isRight()) { + BeEcompErrorManager.getInstance().logBeInvalidConfigurationError("Artifact Upload / Update", "artifactTypes", allArtifactTypes.right().value().name()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.FAILED_RETRIVE_ARTIFACTS_TYPES)); + } + + for (ArtifactType artType : allArtifactTypes.left().value()) { + + if (artType.getName().contains(correctType)) { + resourceInfo.type = artType.getName(); + artifactTypeExist = true; + break; + } + } + + if (!artifactTypeExist) { + BeEcompErrorManager.getInstance().logBeInvalidTypeError("Artifact", "-Not supported artifact type ", correctType); + log.debug("Not supported artifact type = {}", correctType); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED, correctType)); + } + + Either<Boolean, ResponseFormat> eitherNeedToCreate = validateEnv(componentsUtils, createdArtifactTemplateInfoList, resourceInfo); + if (eitherNeedToCreate.isRight()) + return Either.right(eitherNeedToCreate.right().value()); + eitherNeedToCreate = validateParentType(componentsUtils, resourceInfo, parentArtifact); + if (eitherNeedToCreate.isRight()) + return Either.right(eitherNeedToCreate.right().value()); + eitherNeedToCreate = validateIsAlreadyExist(componentsUtils, resourceInfo, createdArtifactTemplateInfoList, parentArtifact); + if (eitherNeedToCreate.isRight()) + return Either.right(eitherNeedToCreate.right().value()); + Set<String> keys = o.keySet(); + for (String key : keys) { + if (o.get(key) instanceof List) { + List<Map<String, Object>> artifList = (List<Map<String, Object>>) o.get(key); + for (Map<String, Object> relatedArtifactsMap : artifList) { + Either<ArtifactTemplateInfo, ResponseFormat> relatedArtifact = ArtifactTemplateInfo.createArtifactTemplateInfoFromJson(componentsUtils, key, relatedArtifactsMap, createdArtifactTemplateInfoList, resourceInfo); + if (relatedArtifact.isRight()) + return relatedArtifact; + if (resourceInfo.relatedArtifactsInfo == null) + resourceInfo.relatedArtifactsInfo = new ArrayList<ArtifactTemplateInfo>(); + resourceInfo.relatedArtifactsInfo.add(relatedArtifact.left().value()); + } + } + } + return Either.left(resourceInfo); + } + + private static Either<Boolean, ResponseFormat> validateIsAlreadyExist(ComponentsUtils componentsUtils, ArtifactTemplateInfo resourceInfo, List<ArtifactTemplateInfo> createdArtifactTemplateInfoList, ArtifactTemplateInfo parentArtifact) { + + if (parentArtifact == null) { + if (createdArtifactTemplateInfoList == null || createdArtifactTemplateInfoList.isEmpty()) + return Either.left(true); + for (ArtifactTemplateInfo createdArtifact : createdArtifactTemplateInfoList) { + if (createdArtifact.getType().equalsIgnoreCase(resourceInfo.getType()) && createdArtifact.getFileName().equalsIgnoreCase(resourceInfo.getFileName())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_MASTER_IN_CSAR, resourceInfo.getFileName(), createdArtifact.type)); + } + } + return Either.left(true); + } else { + List<ArtifactTemplateInfo> relatedArtifacts = parentArtifact.getRelatedArtifactsInfo(); + if (relatedArtifacts == null || relatedArtifacts.isEmpty()) + return Either.left(true); + for (ArtifactTemplateInfo relatedArtifact : relatedArtifacts) { + if (relatedArtifact.getType().equalsIgnoreCase(resourceInfo.getType())) { + if (relatedArtifact.getFileName().equalsIgnoreCase(resourceInfo.getFileName())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_MASTER_IN_CSAR, resourceInfo.getFileName(), parentArtifact.getFileName())); + } + } + } + return Either.left(true); + } + } + + private static Either<Boolean, ResponseFormat> validateParentType(ComponentsUtils componentsUtils, ArtifactTemplateInfo resourceInfo, ArtifactTemplateInfo parentArtifact) { + + if (parentArtifact == null) + return Either.left(true); + if (resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_ARTIFACT.getType())) + return Either.left(true); + if (resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType()) && parentArtifact != null) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_IN_MASTER, resourceInfo.getFileName(), resourceInfo.getType(), parentArtifact.getFileName(), parentArtifact.getType())); + } + if ((resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_NET.getType()) || resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType())) + && !parentArtifact.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_IN_MASTER, resourceInfo.getFileName(), resourceInfo.getType(), parentArtifact.getFileName(), parentArtifact.getType())); + } + if (parentArtifact.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_NESTED.getType())) { + if (resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_ARTIFACT.getType())) { + Either.left(true); + } + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_IN_MASTER, resourceInfo.getFileName(), resourceInfo.getType(), parentArtifact.getFileName(), parentArtifact.getType())); + } + if (parentArtifact.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType()) && resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_IN_MASTER, resourceInfo.getFileName(), resourceInfo.getType(), parentArtifact.getFileName(), parentArtifact.getType())); + } + + if (parentArtifact.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + Either.left(true); + } + return Either.left(true); + } + + private static Either<Boolean, ResponseFormat> validateEnv(ComponentsUtils componentsUtils, List<ArtifactTemplateInfo> createdArtifactTemplateInfoList, ArtifactTemplateInfo resourceInfo) { + + if (createdArtifactTemplateInfoList == null || createdArtifactTemplateInfoList.isEmpty()) + return Either.left(true); + if (resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_NESTED.getType()) || resourceInfo.getType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_ARTIFACT.getType())) + return Either.left(true); + for (ArtifactTemplateInfo createdArtifactTemplateInfo : createdArtifactTemplateInfoList) { + // check if artifact with this name already parsed. If parsed check + // env name. it must be the same. + if (resourceInfo.getFileName().equalsIgnoreCase(createdArtifactTemplateInfo.getFileName())) { + if ((resourceInfo.getEnv() == null || resourceInfo.getEnv().isEmpty()) && (createdArtifactTemplateInfo.getEnv() != null && !createdArtifactTemplateInfo.getEnv().isEmpty())) { + log.debug("Artifact file with name {} type{} already parsed but with env {}", resourceInfo.getFileName(), resourceInfo.getType(), createdArtifactTemplateInfo.getEnv()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_ENV, resourceInfo.getFileName(), resourceInfo.getType(), resourceInfo.getEnv(), createdArtifactTemplateInfo.getEnv())); + } + if (resourceInfo.getEnv() != null && !resourceInfo.getEnv().isEmpty() && createdArtifactTemplateInfo.getEnv() != null && !createdArtifactTemplateInfo.getEnv().isEmpty() + && !createdArtifactTemplateInfo.getEnv().equalsIgnoreCase(resourceInfo.getEnv())) { + log.debug("Artifact file with name {} type{} env {} already parsed but with env {}", resourceInfo.getFileName(), resourceInfo.getType(), resourceInfo.getEnv(), createdArtifactTemplateInfo.getEnv()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_ENV, resourceInfo.getFileName(), resourceInfo.getType(), resourceInfo.getEnv(), createdArtifactTemplateInfo.getEnv())); + } + if ((resourceInfo.getEnv() != null && !resourceInfo.getEnv().isEmpty()) && (createdArtifactTemplateInfo.getEnv() == null || createdArtifactTemplateInfo.getEnv().isEmpty())) { + log.debug("Artifact file with name {} type{} env {} already parsed but with env {}", resourceInfo.getFileName(), resourceInfo.getType(), resourceInfo.getEnv(), createdArtifactTemplateInfo.getEnv()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ARTIFACT_NOT_VALID_ENV, resourceInfo.getFileName(), resourceInfo.getType(), resourceInfo.getEnv(), createdArtifactTemplateInfo.getEnv())); + } + } + List<ArtifactTemplateInfo> relatedArtifacts = createdArtifactTemplateInfo.getRelatedArtifactsInfo(); + Either<Boolean, ResponseFormat> status = validateEnv(componentsUtils, relatedArtifacts, resourceInfo); + if (status.isRight()) + return status; + } + return Either.left(true); + } + + private static Either<List<ArtifactType>, ActionStatus> getDeploymentArtifactTypes(NodeTypeEnum parentType) { + + Map<String, DeploymentArtifactTypeConfig> deploymentArtifacts = null; + List<ArtifactType> artifactTypes = new ArrayList<ArtifactType>(); + + if (parentType.equals(NodeTypeEnum.Service)) { + deploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getServiceDeploymentArtifacts(); + } else { + deploymentArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration().getResourceDeploymentArtifacts(); + } + if (deploymentArtifacts != null) { + for (String artifactType : deploymentArtifacts.keySet()) { + ArtifactType artifactT = new ArtifactType(); + artifactT.setName(artifactType); + artifactTypes.add(artifactT); + } + return Either.left(artifactTypes); + } else { + return Either.right(ActionStatus.GENERAL_ERROR); + } + + } + + public static int compareByGroupName(ArtifactTemplateInfo art1, ArtifactTemplateInfo art2) { + return art1.isBase ? (art2.isBase ? 0 : -1) : (art2.isBase ? 1 : 0); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactTypesInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactTypesInfo.java new file mode 100644 index 0000000000..249b420908 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ArtifactTypesInfo.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +import org.openecomp.sdc.be.model.ArtifactType; + +public class ArtifactTypesInfo { + + Integer heatDefaultTimeout = 60; + List<ArtifactType> artifactTypes; + + public List<ArtifactType> getArtifactTypes() { + return artifactTypes; + } + + public void setArtifactTypes(List<ArtifactType> artifactTypes) { + this.artifactTypes = artifactTypes; + } + + public Integer getHeatDefaultTimeout() { + return heatDefaultTimeout; + } + + public void setHeatDefaultTimeout(Integer heatDefaultTimeout) { + this.heatDefaultTimeout = heatDefaultTimeout; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/CreateAndAssotiateInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/CreateAndAssotiateInfo.java new file mode 100644 index 0000000000..b2fa493443 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/CreateAndAssotiateInfo.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; + +public class CreateAndAssotiateInfo { + private ComponentInstance node; + private RequirementCapabilityRelDef associate; + + public CreateAndAssotiateInfo(ComponentInstance node, RequirementCapabilityRelDef associate) { + super(); + this.node = node; + this.associate = associate; + } + + public ComponentInstance getNode() { + return node; + } + + public void setNode(ComponentInstance node) { + this.node = node; + } + + public RequirementCapabilityRelDef getAssociate() { + return associate; + } + + public void setAssociate(RequirementCapabilityRelDef associate) { + this.associate = associate; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatus.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatus.java new file mode 100644 index 0000000000..d0f3ff868e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatus.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public enum DistributionStatus { + DEPLOYED("Deployed", "DEPLOYED"); + + private String name; + private String auditingStatus; + + private static Logger log = LoggerFactory.getLogger(DistributionStatus.class.getName()); + + DistributionStatus(String name, String auditingStatus) { + this.name = name; + this.auditingStatus = auditingStatus; + } + + public String getName() { + return name; + } + + public String getAuditingStatus() { + return auditingStatus; + } + + public static DistributionStatus getStatusByAuditingStatusName(String auditingStatus) { + DistributionStatus res = null; + DistributionStatus[] values = values(); + for (DistributionStatus value : values) { + if (value.getAuditingStatus().equals(auditingStatus)) { + res = value; + break; + } + } + if (res == null) { + log.debug("No DistributionStatus is mapped to name {}", auditingStatus); + } + return res; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusInfo.java new file mode 100644 index 0000000000..6f7596cd5f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusInfo.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.ESTimeBasedEvent; + +public class DistributionStatusInfo { + String omfComponentID; + String timestamp; + String url; + String status; + String errorReason; + + public DistributionStatusInfo(ESTimeBasedEvent distributionStatusEvent) { + super(); + omfComponentID = (String) distributionStatusEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID.getDisplayName()); + timestamp = (String) distributionStatusEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_STATUS_TIME.getDisplayName());// distributionStatusEvent.getStatusTime(); + url = (String) distributionStatusEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL.getDisplayName());// distributionStatusEvent.getResoureURL(); + status = (String) distributionStatusEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_STATUS.getDisplayName());// distributionStatusEvent.getStatus(); + errorReason = (String) distributionStatusEvent.getFields().get(AuditingFieldsKeysEnum.AUDIT_DESC.getDisplayName()); + + } + + public DistributionStatusInfo(String omfComponentID, String timestamp, String url, String status) { + super(); + this.omfComponentID = omfComponentID; + this.timestamp = timestamp; + this.url = url; + this.status = status; + } + + public String getOmfComponentID() { + return omfComponentID; + } + + public void setOmfComponentID(String omfComponentID) { + this.omfComponentID = omfComponentID; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getErrorReason() { + return errorReason; + } + + public void setErrorReason(String errorReason) { + this.errorReason = errorReason; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusListResponse.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusListResponse.java new file mode 100644 index 0000000000..ab122efc74 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusListResponse.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class DistributionStatusListResponse { + + private List<DistributionStatusInfo> distribStatusInfoList; + + public List<DistributionStatusInfo> getDistributionStatusList() { + return distribStatusInfoList; + } + + public void setDistributionStatusList(List<DistributionStatusInfo> distribStatusInfoList) { + this.distribStatusInfoList = distribStatusInfoList; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusOfServiceInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusOfServiceInfo.java new file mode 100644 index 0000000000..dfa481d34d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusOfServiceInfo.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +public class DistributionStatusOfServiceInfo { + String distributionID; + String timestamp; + String userId; + String deployementStatus; + + public DistributionStatusOfServiceInfo() { + super(); + + } + + public DistributionStatusOfServiceInfo(String distributionID, String timestamp, String userId, String deployementStatus) { + super(); + this.distributionID = distributionID; + this.timestamp = timestamp; + this.userId = userId; + this.deployementStatus = deployementStatus; + } + + public String getDistributionID() { + return distributionID; + } + + public void setDistributionID(String distributionID) { + this.distributionID = distributionID; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDeployementStatus() { + return deployementStatus; + } + + public void setDeployementStatus(String deployementStatus) { + this.deployementStatus = deployementStatus; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusOfServiceListResponce.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusOfServiceListResponce.java new file mode 100644 index 0000000000..8415736be1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/DistributionStatusOfServiceListResponce.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class DistributionStatusOfServiceListResponce { + + private List<DistributionStatusOfServiceInfo> distribStatusOfServiceInfoList; + + public List<DistributionStatusOfServiceInfo> getDistributionStatusOfServiceList() { + return distribStatusOfServiceInfoList; + } + + public void setDistributionStatusOfServiceList(List<DistributionStatusOfServiceInfo> distribStatusOfServiceInfoList) { + this.distribStatusOfServiceInfoList = distribStatusOfServiceInfoList; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/GroupDefinitionInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/GroupDefinitionInfo.java new file mode 100644 index 0000000000..24d9c5644d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/GroupDefinitionInfo.java @@ -0,0 +1,130 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; +import org.openecomp.sdc.be.model.GroupDefinition; + +public class GroupDefinitionInfo { + private String name; + + // the id is unique per group instance on graph. + private String uniqueId; + + // the group UUID should be changed when one of the artifacts/component + // instances has been changed. + private String groupUUID; + + // version should be changed when there is a change to the group's metadata + // or to the groups members + // (not necessarily when the VF version is changed). This field cannot be + // updated by user + private String version; + + private String invariantUUID; + + Boolean isBase = null; + + // artifacts - list of artifact uid. All artifacts in the group must already + // be uploaded to the VF + private List<ArtifactDefinitionInfo> artifacts; + + public GroupDefinitionInfo() { + super(); + } + + public GroupDefinitionInfo(GroupDefinition other) { + this.setName(other.getName()); + this.setUniqueId(other.getUniqueId()); + this.setVersion(other.getVersion()); + this.setGroupUUID(other.getGroupUUID()); + this.setInvariantUUID(other.getInvariantUUID()); + + } + + public String getInvariantUUID() { + return invariantUUID; + } + + public void setInvariantUUID(String invariantUUID) { + this.invariantUUID = invariantUUID; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getGroupUUID() { + return groupUUID; + } + + public void setGroupUUID(String groupUUID) { + this.groupUUID = groupUUID; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Boolean getIsBase() { + return isBase; + } + + public void setIsBase(Boolean isBase) { + this.isBase = isBase; + } + + public List<ArtifactDefinitionInfo> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List<ArtifactDefinitionInfo> artifacts) { + this.artifacts = artifacts; + } + + @Override + public String toString() { + return "GroupDefinitionInfo [" + super.toString() + ", isBase=" + isBase + ", artifacts=" + artifacts + "]"; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/GroupTemplateInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/GroupTemplateInfo.java new file mode 100644 index 0000000000..8471a801ac --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/GroupTemplateInfo.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; +import java.util.Map; + +public class GroupTemplateInfo { + String groupName; + boolean isBase; + ArtifactTemplateInfo artifactTemplateInfo; + + public GroupTemplateInfo() { + super(); + // TODO Auto-generated constructor stub + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public boolean isBase() { + return isBase; + } + + public void setBase(boolean isBase) { + this.isBase = isBase; + } + + public ArtifactTemplateInfo getArtifactTemplateInfo() { + return artifactTemplateInfo; + } + + public void setArtifactTemplateInfo(ArtifactTemplateInfo artifactTemplateInfo) { + this.artifactTemplateInfo = artifactTemplateInfo; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/MergedArtifactInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/MergedArtifactInfo.java new file mode 100644 index 0000000000..95038b1830 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/MergedArtifactInfo.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.model.ArtifactDefinition; + +public class MergedArtifactInfo { + + private List<ArtifactDefinition> createdArtifact; + private ArtifactTemplateInfo jsonArtifactTemplate; + private Set<String> parsetArtifactsNames; + + public List<ArtifactDefinition> getCreatedArtifact() { + return createdArtifact; + } + + public void setCreatedArtifact(List<ArtifactDefinition> createdArtifact) { + this.createdArtifact = createdArtifact; + parsetArtifactsNames = new HashSet<String>(); + parsetArtifactsNames.add(jsonArtifactTemplate.getFileName()); + List<ArtifactTemplateInfo> relatedGroupTemplateList = jsonArtifactTemplate.getRelatedArtifactsInfo(); + if (relatedGroupTemplateList != null && !relatedGroupTemplateList.isEmpty()) { + this.createArtifactsGroupSet(relatedGroupTemplateList, parsetArtifactsNames); + } + + } + + public ArtifactTemplateInfo getJsonArtifactTemplate() { + return jsonArtifactTemplate; + } + + public void setJsonArtifactTemplate(ArtifactTemplateInfo jsonArtifactTemplate) { + this.jsonArtifactTemplate = jsonArtifactTemplate; + } + + public List<ArtifactTemplateInfo> getListToAssociateArtifactToGroup() { + List<ArtifactTemplateInfo> resList = new ArrayList<ArtifactTemplateInfo>(); + List<ArtifactTemplateInfo> relatedArtifacts = jsonArtifactTemplate.getRelatedArtifactsInfo(); + if (relatedArtifacts != null && !relatedArtifacts.isEmpty()) { + getNewArtifactsInGroup(resList, relatedArtifacts); + } + return resList; + } + + public List<ArtifactDefinition> getListToDissotiateArtifactFromGroup(List<ArtifactDefinition> deletedArtifacts) { + List<ArtifactDefinition> resList = new ArrayList<ArtifactDefinition>(); + for (ArtifactDefinition artifactDefinition : createdArtifact) { + if (!parsetArtifactsNames.contains(artifactDefinition.getArtifactName())) { + boolean isDeleted = false; + for (ArtifactDefinition deletedArtifact : deletedArtifacts) { + if (artifactDefinition.getUniqueId().equalsIgnoreCase(deletedArtifact.getUniqueId())) { + isDeleted = true; + break; + } + + } + if (!isDeleted) + resList.add(artifactDefinition); + } + + } + + return resList; + } + + public List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>> getListToUpdateArtifactInGroup() { + List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>> resList = new ArrayList<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>>(); + for (ArtifactDefinition artifactDefinition : createdArtifact) { + if (artifactDefinition.getArtifactName().equalsIgnoreCase(jsonArtifactTemplate.getFileName())) { + resList.add(new ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>(artifactDefinition, jsonArtifactTemplate)); + } + } + List<ArtifactTemplateInfo> relatedArtifacts = jsonArtifactTemplate.getRelatedArtifactsInfo(); + if (relatedArtifacts != null && !relatedArtifacts.isEmpty()) { + getUpdateArtifactsInGroup(resList, relatedArtifacts); + } + return resList; + } + + private void getUpdateArtifactsInGroup(List<ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>> resList, List<ArtifactTemplateInfo> jsonArtifacts) { + + for (ArtifactTemplateInfo artifactTemplateInfo : jsonArtifacts) { + + for (ArtifactDefinition artifactDefinition : createdArtifact) { + if (artifactDefinition.getArtifactName().equalsIgnoreCase(artifactTemplateInfo.getFileName())) { + resList.add(new ImmutablePair<ArtifactDefinition, ArtifactTemplateInfo>(artifactDefinition, artifactTemplateInfo)); + } + } + + List<ArtifactTemplateInfo> relatedArtifacts = artifactTemplateInfo.getRelatedArtifactsInfo(); + if (relatedArtifacts != null && !relatedArtifacts.isEmpty()) { + getUpdateArtifactsInGroup(resList, relatedArtifacts); + } + } + } + + private void getNewArtifactsInGroup(List<ArtifactTemplateInfo> resList, List<ArtifactTemplateInfo> jsonArtifacts) { + + for (ArtifactTemplateInfo artifactTemplateInfo : jsonArtifacts) { + boolean isNewArtifact = true; + for (ArtifactDefinition artifactDefinition : createdArtifact) { + if (artifactDefinition.getArtifactName().equalsIgnoreCase(artifactTemplateInfo.getFileName())) { + isNewArtifact = false; + } + } + if (isNewArtifact) + resList.add(artifactTemplateInfo); + List<ArtifactTemplateInfo> relatedArtifacts = artifactTemplateInfo.getRelatedArtifactsInfo(); + if (relatedArtifacts != null && !relatedArtifacts.isEmpty()) { + getNewArtifactsInGroup(resList, relatedArtifacts); + } + } + } + + private void createArtifactsGroupSet(List<ArtifactTemplateInfo> parsedGroupTemplateList, Set<String> parsedArtifactsName) { + + for (ArtifactTemplateInfo parsedGroupTemplate : parsedGroupTemplateList) { + parsedArtifactsName.add(parsedGroupTemplate.getFileName()); + List<ArtifactTemplateInfo> relatedArtifacts = parsedGroupTemplate.getRelatedArtifactsInfo(); + if (relatedArtifacts != null && !relatedArtifacts.isEmpty()) { + createArtifactsGroupSet(relatedArtifacts, parsedArtifactsName); + } + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServiceInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServiceInfo.java new file mode 100644 index 0000000000..457c49ee8e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServiceInfo.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class ServiceInfo { + + private String name; + private List<ServiceVersionInfo> versions; + + public ServiceInfo(String serviceName, List<ServiceVersionInfo> list) { + this.name = serviceName; + this.versions = list; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List<ServiceVersionInfo> getVersions() { + return versions; + } + + public void setVersions(List<ServiceVersionInfo> versions) { + this.versions = versions; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServiceVersionInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServiceVersionInfo.java new file mode 100644 index 0000000000..13f8a1307f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServiceVersionInfo.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +public class ServiceVersionInfo { + + // private String serviceName; + private String version; + private String url; + + public ServiceVersionInfo(String serviceName, String serviceVersion, String context) { + super(); + // this.serviceName = serviceName; + this.version = serviceVersion; + StringBuilder sb = new StringBuilder(context); + sb.append("services/").append(serviceName).append("/").append(serviceVersion); + url = sb.toString(); + } + + public String getVersion() { + return version; + } + + public void setVersion(String serviceVersion) { + this.version = serviceVersion; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServicesWrapper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServicesWrapper.java new file mode 100644 index 0000000000..9c26cf5959 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServicesWrapper.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class ServicesWrapper { + private List<ServiceInfo> services; + + public List<ServiceInfo> getServices() { + return services; + } + + public void setServices(List<ServiceInfo> services) { + this.services = services; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServletJsonResponse.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServletJsonResponse.java new file mode 100644 index 0000000000..5559311e9e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ServletJsonResponse.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +public class ServletJsonResponse { + + String source; + String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ToscaNodeTypeInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ToscaNodeTypeInfo.java new file mode 100644 index 0000000000..11b27af7a1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ToscaNodeTypeInfo.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class ToscaNodeTypeInfo { + + private String nodeName; + private String templateVersion; + private List<ToscaNodeTypeInterface> interfaces; + private String iconPath; + + public String getNodeName() { + return nodeName; + } + + public void setNodeName(String nodeName) { + this.nodeName = nodeName; + } + + public String getTemplateVersion() { + return templateVersion; + } + + public void setTemplateVersion(String templateVersion) { + this.templateVersion = templateVersion; + } + + public List<ToscaNodeTypeInterface> getInterfaces() { + return interfaces; + } + + public void setInterfaces(List<ToscaNodeTypeInterface> interfaces) { + this.interfaces = interfaces; + } + + public String getIconPath() { + return iconPath; + } + + public void setIconPath(String iconPath) { + this.iconPath = iconPath; + } + + @Override + public String toString() { + return "ToscaNodeTypeInfo [nodeName=" + nodeName + ", templateVersion=" + templateVersion + ", interfaces=" + interfaces + ", iconPath=" + iconPath + "]"; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/info/ToscaNodeTypeInterface.java b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ToscaNodeTypeInterface.java new file mode 100644 index 0000000000..25bab766bf --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/info/ToscaNodeTypeInterface.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.info; + +import java.util.List; + +public class ToscaNodeTypeInterface { + + List<String> scripts; + + public List<String> getScripts() { + return scripts; + } + + public void setScripts(List<String> scripts) { + this.scripts = scripts; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java b/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java new file mode 100644 index 0000000000..d40a3d4433 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java @@ -0,0 +1,132 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.listen; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.impl.DownloadArtifactLogic; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.monitoring.BeMonitoringService; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.common.listener.AppContextListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import org.openecomp.portalsdk.core.onboarding.ueb.UebException; +import org.openecomp.portalsdk.core.onboarding.ueb.UebManager; + +public class BEAppContextListener extends AppContextListener implements ServletContextListener { + + private static final String MANIFEST_FILE_NAME = "/META-INF/MANIFEST.MF"; + private static Logger log = LoggerFactory.getLogger(BEAppContextListener.class.getName()); + + private static UebManager uebManager = null; + + public void contextInitialized(ServletContextEvent context) { + + super.contextInitialized(context); + + ConfigurationManager configurationManager = new ConfigurationManager(ExternalConfiguration.getConfigurationSource()); + log.debug("loading configuration from configDir: {} appName: {}", ExternalConfiguration.getConfigDir(), ExternalConfiguration.getAppName()); + + context.getServletContext().setAttribute(Constants.CONFIGURATION_MANAGER_ATTR, configurationManager); + + WebAppContextWrapper webAppContextWrapper = new WebAppContextWrapper(); + context.getServletContext().setAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR, webAppContextWrapper); + + DownloadArtifactLogic downloadArtifactLogic = new DownloadArtifactLogic(); + context.getServletContext().setAttribute(Constants.DOWNLOAD_ARTIFACT_LOGIC_ATTR, downloadArtifactLogic); + + context.getServletContext().setAttribute(Constants.SDC_RELEASE_VERSION_ATTR, getVersionFromManifest(context)); + + // Monitoring service + BeMonitoringService bms = new BeMonitoringService(context.getServletContext()); + bms.start(configurationManager.getConfiguration().getSystemMonitoring().getProbeIntervalInSeconds(15)); + + initUebManager(); + + log.debug("After executing {}", this.getClass()); + + } + + private void initUebManager() { + try { + if (uebManager == null) { + uebManager = UebManager.getInstance(); + uebManager.initListener(null); + } + } catch (UebException ex) { + log.debug("Failed to initialize UebManager", ex); + BeEcompErrorManager.getInstance().logInternalConnectionError("InitUebManager", "Failed to initialize listener of UebManager", ErrorSeverity.ERROR); + } + log.debug("After init listener of UebManager"); + } + + public void contextDestroyed(ServletContextEvent context) { + if (uebManager != null) { + uebManager.shutdown(); + uebManager = null; + } + super.contextDestroyed(context); + + } + + private IResourceOperation getResourceOperationManager(Class<? extends IResourceOperation> clazz, WebApplicationContext webContext) { + + return webContext.getBean(clazz); + } + + private String getVersionFromManifest(ServletContextEvent context) { + ServletContext servletContext = context.getServletContext(); + InputStream inputStream = servletContext.getResourceAsStream(MANIFEST_FILE_NAME); + + String version = null; + try { + Manifest mf = new Manifest(inputStream); + Attributes atts = mf.getMainAttributes(); + version = atts.getValue(Constants.SDC_RELEASE_VERSION_ATTR); + if (version == null || version.isEmpty()) { + log.warn("failed to read ASDC version from MANIFEST."); + } else { + log.info("ASDC version from MANIFEST is {}", version); + } + + } catch (IOException e) { + log.warn("failed to read ASDC version from MANIFEST", e.getMessage()); + } + + return version; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/monitoring/EsGateway.java b/catalog-be/src/main/java/org/openecomp/sdc/be/monitoring/EsGateway.java new file mode 100644 index 0000000000..34a56cdd13 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/monitoring/EsGateway.java @@ -0,0 +1,109 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.monitoring; + +import java.net.URI; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.proxy.ProxyServlet; +import org.openecomp.sdc.be.components.impl.MonitoringBusinessLogic; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.common.api.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +public class EsGateway extends ProxyServlet { + + private static final long serialVersionUID = 1L; + private static Logger log = LoggerFactory.getLogger(EsGateway.class.getName()); + + @Override + public URI rewriteURI(HttpServletRequest request) { + + String originalUrl = request.getRequestURI(); + + String redirectedUrl = getModifiedUrl(request); + + log.debug("EsGateway Redirecting request from: {} , to: {}", originalUrl, redirectedUrl); + return URI.create(redirectedUrl); + } + + @Override + public void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) { + super.customizeProxyRequest(proxyRequest, request); + + } + + @Override + protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse) { + super.onResponseSuccess(request, response, proxyResponse); + } + + public String getModifiedUrl(HttpServletRequest request) { + String esHost = null; + String esPort = null; + MonitoringBusinessLogic monitoringBL = getMonitoringBL(request.getSession().getServletContext()); + if (monitoringBL == null) { + log.error("failed to retrive monitoringBL."); + } else { + esHost = monitoringBL.getEsHost(); + esPort = monitoringBL.getEsPort(); + } + + String scheme = request.getScheme(); + String contextPath = request.getContextPath(); // /mywebapp + String servletPath = request.getServletPath(); // /servlet/MyServlet + String pathInfo = request.getPathInfo(); // /a/b;c=123 + String queryString = request.getQueryString(); // d=789 + + StringBuilder url = new StringBuilder(); + url.append(scheme).append("://").append(esHost); + url.append(":").append(esPort); + url.append(contextPath).append(servletPath); + + if (pathInfo != null) { + url.append(pathInfo); + } + if (queryString != null) { + url.append("?").append(queryString); + } + + String redirectedUrl = url.toString().replace("/sdc2/esGateway/", "/"); + return redirectedUrl; + + } + + protected MonitoringBusinessLogic getMonitoringBL(ServletContext context) { + + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + MonitoringBusinessLogic monitoringBusinessLogic = webApplicationContext.getBean(MonitoringBusinessLogic.class); + + return monitoringBusinessLogic; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java new file mode 100644 index 0000000000..0e8addf692 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java @@ -0,0 +1,843 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.zip.ZipInputStream; + +import javax.annotation.Resource; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Response; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.codehaus.jackson.map.ObjectMapper; +import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.components.impl.CsarValidationUtils; +import org.openecomp.sdc.be.components.impl.ImportUtils; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +import org.openecomp.sdc.be.components.impl.ResourceImportManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.ServletUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.UploadResourceInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.servlets.ResourceUploadServlet.ResourceAuthorityTypeEnum; +import org.openecomp.sdc.be.user.IUserBusinessLogic; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.api.UploadArtifactInfo; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.util.YamlToObjectConverter; +import org.openecomp.sdc.common.util.ZipUtil; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.context.WebApplicationContext; +import org.yaml.snakeyaml.Yaml; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +import fj.data.Either; + +public abstract class AbstractValidationsServlet extends BeGenericServlet { + + @Resource + private ServletUtils servletUtils; + + @Resource + private ResourceImportManager resourceImportManager; + + @Autowired + protected ComponentsUtils componentsUtils; + + private static final Object LOCK = new Object(); + private Logger log = null; + + protected void init(Logger log) { + initLog(log); + initSpringFromContext(); + + } + + private void initLog(Logger log) { + if (this.log == null) { + synchronized (LOCK) { + if (this.log == null) { + this.log = log; + } + + } + } + } + + private void initSpringFromContext() { + if (servletUtils == null) { + synchronized (LOCK) { + if (servletUtils == null) { + ServletContext context = servletRequest.getSession().getServletContext(); + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + servletUtils = webApplicationContext.getBean(ServletUtils.class); + resourceImportManager = webApplicationContext.getBean(ResourceImportManager.class); + } + } + } + } + + protected void validateResourceDoesNotExist(Wrapper<Response> responseWrapper, User user, String resourceName) { + if (resourceImportManager.isResourceExist(resourceName)) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.RESOURCE_ALREADY_EXISTS); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceName); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + } + + protected void validateUserExist(Wrapper<Response> responseWrapper, Wrapper<User> userWrapper, String userId) { + log.debug("get user {} from DB", userId); + // get user details + if (userId == null) { + log.info("user userId is null"); + Response response = returnMissingInformation(new User()); + responseWrapper.setInnerElement(response); + } + + else { + IUserBusinessLogic userAdmin = getServletUtils().getUserAdmin(); + Either<User, ActionStatus> eitherCreator = userAdmin.getUser(userId, false); + if (eitherCreator.isRight()) { + log.info("user is not listed. userId={}", userId); + User user = new User(); + user.setUserId(userId); + Response response = returnMissingInformation(user); + responseWrapper.setInnerElement(response); + } else { + userWrapper.setInnerElement(eitherCreator.left().value()); + } + } + } + + protected Response returnMissingInformation(User user) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_INFORMATION); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + return buildErrorResponse(responseFormat); + } + + protected void validateDataNotNull(Wrapper<Response> responseWrapper, Object... dataParams) { + for (Object dataElement : dataParams) { + if (dataElement == null) { + log.info("Invalid body was received."); + Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + responseWrapper.setInnerElement(response); + break; + } + } + + } + + protected void validateUserRole(Wrapper<Response> errorResponseWrapper, User user) { + log.debug("validate user role"); + if (!user.getRole().equals(Role.ADMIN.name()) && !user.getRole().equals(Role.DESIGNER.name())) { + log.info("user is not in appropriate role to perform action"); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + log.debug("audit before sending response"); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + + Response response = buildErrorResponse(responseFormat); + errorResponseWrapper.setInnerElement(response); + } + + } + + protected void validateZip(Wrapper<Response> responseWrapper, File file, String payloadName) throws FileNotFoundException { + InputStream fileInputStream = new FileInputStream(file); + Map<String, byte[]> unzippedFolder = ZipUtil.readZip(new ZipInputStream(fileInputStream)); + if (payloadName == null || payloadName.isEmpty() || !unzippedFolder.containsKey(payloadName)) { + log.info("Invalid json was received. payloadName should be yml file name"); + Response errorResponse = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + responseWrapper.setInnerElement(errorResponse); + } + + } + + protected void fillZipContents(Wrapper<String> yamlStringWrapper, File file) throws FileNotFoundException { + InputStream fileInputStream = new FileInputStream(file); + Map<String, byte[]> unzippedFolder = ZipUtil.readZip(new ZipInputStream(fileInputStream)); + String ymlName = unzippedFolder.keySet().iterator().next(); + fillToscaTemplateFromZip(yamlStringWrapper, ymlName, file); + } + + protected void fillToscaTemplateFromZip(Wrapper<String> yamlStringWrapper, String payloadName, File file) throws FileNotFoundException { + InputStream fileInputStream = new FileInputStream(file); + Map<String, byte[]> unzippedFolder = ZipUtil.readZip(new ZipInputStream(fileInputStream)); + byte[] yamlFileInBytes = unzippedFolder.get(payloadName); + String yamlAsString = new String(yamlFileInBytes, StandardCharsets.UTF_8); + log.debug("received yaml: {}", yamlAsString); + yamlStringWrapper.setInnerElement(yamlAsString); + } + + protected void validateUserRole(Wrapper<Response> errorResponseWrapper, User user, ResourceAuthorityTypeEnum resourceAuthority) { + log.debug("validate user role"); + if (resourceAuthority == ResourceAuthorityTypeEnum.NORMATIVE_TYPE_BE) { + if (!user.getRole().equals(Role.ADMIN.name())) { + log.info("user is not in appropriate role to perform action"); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + log.debug("audit before sending response"); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + + Response response = buildErrorResponse(responseFormat); + errorResponseWrapper.setInnerElement(response); + } + } else { + validateUserRole(errorResponseWrapper, user); + } + + } + + protected void validateAndFillResourceJson(Wrapper<Response> responseWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, User user, ResourceAuthorityTypeEnum resourceAuthorityEnum, String resourceInfo) { + boolean isValid; + try { + log.debug("The received json is {}", resourceInfo); + UploadResourceInfo resourceInfoObject = gson.fromJson(resourceInfo, UploadResourceInfo.class); + if (resourceInfoObject == null) { + isValid = false; + } else { + if (!resourceAuthorityEnum.isBackEndImport()) { + isValid = resourceInfoObject.getPayloadName() != null && !resourceInfoObject.getPayloadName().isEmpty(); + // TODO Tal only resource name is checked + } else { + isValid = true; + } + uploadResourceInfoWrapper.setInnerElement(resourceInfoObject); + } + + } catch (JsonSyntaxException e) { + isValid = false; + + } + if (!isValid) { + log.info("Invalid json was received."); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, null); + Response errorResp = buildErrorResponse(responseFormat); + responseWrapper.setInnerElement(errorResp); + } + } + + protected void validateAuthorityType(Wrapper<Response> responseWrapper, String authorityType) { + log.debug("The received authority type is {}", authorityType); + ResourceAuthorityTypeEnum authorityTypeEnum = ResourceAuthorityTypeEnum.findByUrlPath(authorityType); + if (authorityTypeEnum == null) { + log.info("Invalid authority type was received."); + Response errorResp = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + responseWrapper.setInnerElement(errorResp); + } + } + + public ServletUtils getServletUtils() { + initSpringFromContext(); + return servletUtils; + } + + public Gson getGson() { + return getServletUtils().getGson(); + } + + public ComponentsUtils getComponentsUtils() { + return getServletUtils().getComponentsUtils(); + } + + protected void validatePayloadIsTosca(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user, String toscaPayload) { + log.debug("checking payload is valid tosca"); + boolean isValid; + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(toscaPayload)) ? new String(Base64.decodeBase64(toscaPayload)) : toscaPayload; + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + Either<String, ResultStatusEnum> findFirstToscaStringElement = ImportUtils.findFirstToscaStringElement(mappedToscaTemplate, ToscaTagNamesEnum.TOSCA_VERSION); + + if (findFirstToscaStringElement.isRight()) { + isValid = false; + } else { + String defenitionVersionFound = findFirstToscaStringElement.left().value(); + if (defenitionVersionFound == null || defenitionVersionFound.isEmpty()) { + isValid = false; + } else { + isValid = ImportUtils.Constants.TOSCA_DEFINITION_VERSIONS.contains(defenitionVersionFound); + } + } + + if (!isValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_TEMPLATE); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + + } + + protected void validatePayloadIsYml(Wrapper<Response> responseWrapper, User user, UploadResourceInfo uploadResourceInfo, String toscaTamplatePayload) { + log.debug("checking tosca template is valid yml"); + YamlToObjectConverter yamlConvertor = new YamlToObjectConverter(); + boolean isYamlValid = yamlConvertor.isValidYaml(toscaTamplatePayload.getBytes()); + if (!isYamlValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_YAML_FILE); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + } + + protected void validatePayloadNameSpace(Wrapper<Response> responseWrapper, UploadResourceInfo resourceInfo, User user, String toscaPayload) { + boolean isValid; + String nameSpace = ""; + + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(toscaPayload)) ? new String(Base64.decodeBase64(toscaPayload)) : toscaPayload; + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(mappedToscaTemplate, ToscaTagNamesEnum.NODE_TYPES); + if (toscaElement.isRight() || toscaElement.left().value().size() != 1) { + isValid = false; + } else { + nameSpace = toscaElement.left().value().keySet().iterator().next(); + isValid = nameSpace.startsWith(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX); + } + if (!isValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_RESOURCE_NAMESPACE); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } else { + String str1 = nameSpace.substring(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX.length()); + String[] findTypes = str1.split("\\."); + if (ResourceTypeEnum.contains(findTypes[0].toUpperCase())) { + String type = findTypes[0].toUpperCase(); + resourceInfo.setResourceType(type); + } else { + resourceInfo.setResourceType(ResourceTypeEnum.VFC.name()); + } + } + + } + + protected void validatePayloadIsSingleResource(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user, String toscaPayload) { + log.debug("checking payload contains single resource"); + boolean isValid; + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(toscaPayload)) ? new String(Base64.decodeBase64(toscaPayload)) : toscaPayload; + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(mappedToscaTemplate, ToscaTagNamesEnum.NODE_TYPES); + if (toscaElement.isRight()) { + isValid = false; + } else { + isValid = toscaElement.left().value().size() == 1; + } + + if (!isValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_SINGLE_RESOURCE); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + + } + + protected void validatePayloadIsNotService(Wrapper<Response> responseWrapper, User user, UploadResourceInfo uploadResourceInfo, String toscaPayload) { + log.debug("checking payload is not a tosca service"); + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(toscaPayload)) ? new String(Base64.decodeBase64(toscaPayload)) : toscaPayload; + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + Either<Object, ResultStatusEnum> toscaElement = ImportUtils.findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.TOPOLOGY_TEMPLATE, ToscaElementTypeEnum.ALL); + + if (toscaElement.isLeft()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_RESOURCE_TOSCA_TEMPLATE); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + + } + + protected void validatePayloadIsTopologyTemplate(Wrapper<Response> responseWrapper, User user, UploadResourceInfo uploadResourceInfo, String toscaPayload) { + log.debug("checking payload is a tosca topology template"); + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(toscaPayload)) ? new String(Base64.decodeBase64(toscaPayload)) : toscaPayload; + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + Either<Object, ResultStatusEnum> toscaElement = ImportUtils.findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.TOPOLOGY_TEMPLATE, ToscaElementTypeEnum.ALL); + + if (toscaElement.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_TOPOLOGY_TOSCA_TEMPLATE); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + + } + + protected void validateToscaTemplatePayloadName(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user) { + String toscaTemplatePayloadName = uploadResourceInfo.getPayloadName(); + boolean isValidSuffix = false; + if (toscaTemplatePayloadName != null && !toscaTemplatePayloadName.isEmpty()) { + for (String validSuffix : ImportUtils.Constants.TOSCA_YML_CSAR_VALID_SUFFIX) { + isValidSuffix = isValidSuffix || toscaTemplatePayloadName.toLowerCase().endsWith(validSuffix); + } + } + if (!isValidSuffix) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_FILE_EXTENSION); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + + } + + protected void validateMD5(Wrapper<Response> responseWrapper, User user, UploadResourceInfo resourceInfo, HttpServletRequest request, String resourceInfoJsonString) { + boolean isValid; + String recievedMD5 = request.getHeader(Constants.MD5_HEADER); + if (recievedMD5 == null) { + isValid = false; + } else { + String calculateMD5 = GeneralUtility.calculateMD5ByString(resourceInfoJsonString); + isValid = calculateMD5.equals(recievedMD5); + } + if (!isValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_RESOURCE_CHECKSUM); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + } + + protected void validateComponentType(Wrapper<Response> responseWrapper, Wrapper<ComponentTypeEnum> componentWrapper, String componentType) { + boolean isValid; + if (componentType == null) { + isValid = false; + } else { + if (ComponentTypeEnum.RESOURCE_PARAM_NAME.equalsIgnoreCase(componentType)) { + isValid = true; + componentWrapper.setInnerElement(ComponentTypeEnum.RESOURCE); + } else if (ComponentTypeEnum.SERVICE_PARAM_NAME.equalsIgnoreCase(componentType)) { + isValid = true; + componentWrapper.setInnerElement(ComponentTypeEnum.SERVICE); + } else { + isValid = false; + } + } + if (!isValid) { + log.debug("Invalid componentType:{}", componentType); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + Response errorResp = buildErrorResponse(responseFormat); + responseWrapper.setInnerElement(errorResp); + } + } + + protected void fillToscaTemplateFromJson(Wrapper<Response> responseWrapper, Wrapper<String> yamlStringWrapper, User user, UploadResourceInfo resourceInfo) { + if (resourceInfo.getPayloadData() == null || resourceInfo.getPayloadData().isEmpty()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_RESOURCE_PAYLOAD); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } else { + String toscaPayload = resourceInfo.getPayloadData(); + String decodedPayload = (GeneralUtility.isBase64Encoded(toscaPayload)) ? new String(Base64.decodeBase64(toscaPayload)) : toscaPayload; + yamlStringWrapper.setInnerElement(decodedPayload); + } + + } + + protected void fillPayload(Wrapper<Response> responseWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, Wrapper<String> yamlStringWrapper, User user, String resourceInfoJsonString, ResourceAuthorityTypeEnum resourceAuthorityEnum, + File file) throws FileNotFoundException { + + if (responseWrapper.isEmpty()) { + if (resourceAuthorityEnum.isBackEndImport()) { + // PrePayload Validations + if (responseWrapper.isEmpty()) { + validateDataNotNull(responseWrapper, file, resourceInfoJsonString); + } + if (responseWrapper.isEmpty()) { + validateZip(responseWrapper, file, uploadResourceInfoWrapper.getInnerElement().getPayloadName()); + } + + // Fill PayLoad From File + if (responseWrapper.isEmpty()) { + fillToscaTemplateFromZip(yamlStringWrapper, uploadResourceInfoWrapper.getInnerElement().getPayloadName(), file); + } + + } else { + // Fill PayLoad From JSON + if (responseWrapper.isEmpty()) { + fillToscaTemplateFromJson(responseWrapper, yamlStringWrapper, user, uploadResourceInfoWrapper.getInnerElement()); + } + } + + } + + } + + protected void specificResourceAuthorityValidations(Wrapper<Response> responseWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, Wrapper<String> yamlStringWrapper, User user, HttpServletRequest request, String resourceInfoJsonString, + ResourceAuthorityTypeEnum resourceAuthorityEnum) throws FileNotFoundException { + + if (responseWrapper.isEmpty()) { + // UI Only Validation + if (!resourceAuthorityEnum.isBackEndImport()) { + importUIValidations(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), user, request, resourceInfoJsonString); + } + + // User Defined Type Resources + if (resourceAuthorityEnum.isUserTypeResource() && !CsarValidationUtils.isCsarPayloadName(uploadResourceInfoWrapper.getInnerElement().getPayloadName())) { + if (responseWrapper.isEmpty()) { + validatePayloadNameSpace(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), user, yamlStringWrapper.getInnerElement()); + } + + } + } + } + + protected void commonGeneralValidations(Wrapper<Response> responseWrapper, Wrapper<User> userWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, ResourceAuthorityTypeEnum resourceAuthorityEnum, String userId, + String resourceInfoJsonString) { + + if (responseWrapper.isEmpty()) { + validateUserExist(responseWrapper, userWrapper, userId); + } + + if (responseWrapper.isEmpty()) { + validateUserRole(responseWrapper, userWrapper.getInnerElement(), resourceAuthorityEnum); + } + + if (responseWrapper.isEmpty()) { + validateAndFillResourceJson(responseWrapper, uploadResourceInfoWrapper, userWrapper.getInnerElement(), resourceAuthorityEnum, resourceInfoJsonString); + } + + if (responseWrapper.isEmpty()) { + validateToscaTemplatePayloadName(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), userWrapper.getInnerElement()); + } + if (responseWrapper.isEmpty()) { + validateResourceType(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), userWrapper.getInnerElement()); + } + + } + + private void validateResourceType(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user) { + String resourceType = uploadResourceInfo.getResourceType(); + if (resourceType == null || !ResourceTypeEnum.contains(resourceType)) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + Response errorResponse = buildErrorResponse(responseFormat); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, uploadResourceInfo.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + responseWrapper.setInnerElement(errorResponse); + } + } + + protected void importUIValidations(Wrapper<Response> responseWrapper, UploadResourceInfo resourceInfo, User user, HttpServletRequest request, String resourceInfoJsonString) { + if (responseWrapper.isEmpty()) { + validateMD5(responseWrapper, user, resourceInfo, request, resourceInfoJsonString); + } + if (responseWrapper.isEmpty() && request != null && request.getMethod() != null && request.getMethod().equals("POST")) { + validateResourceDoesNotExist(responseWrapper, user, resourceInfo.getName()); + } + } + + protected void commonPayloadValidations(Wrapper<Response> responseWrapper, Wrapper<String> yamlStringWrapper, User user, UploadResourceInfo uploadResourceInfo) { + + if (responseWrapper.isEmpty()) { + validatePayloadIsYml(responseWrapper, user, uploadResourceInfo, yamlStringWrapper.getInnerElement()); + } + if (responseWrapper.isEmpty()) { + validatePayloadIsTosca(responseWrapper, uploadResourceInfo, user, yamlStringWrapper.getInnerElement()); + } + if (responseWrapper.isEmpty()) { + validatePayloadIsNotService(responseWrapper, user, uploadResourceInfo, yamlStringWrapper.getInnerElement()); + } + if (responseWrapper.isEmpty()) { + validatePayloadIsSingleResource(responseWrapper, uploadResourceInfo, user, yamlStringWrapper.getInnerElement()); + } + } + + protected void topologyTemplatePayloadValidations(Wrapper<Response> responseWrapper, Wrapper<String> yamlStringWrapper, User user, UploadResourceInfo uploadResourceInfo) { + + if (responseWrapper.isEmpty()) { + validatePayloadIsYml(responseWrapper, user, uploadResourceInfo, yamlStringWrapper.getInnerElement()); + } + if (responseWrapper.isEmpty()) { + validatePayloadIsTosca(responseWrapper, uploadResourceInfo, user, yamlStringWrapper.getInnerElement()); + } + if (responseWrapper.isEmpty()) { + validatePayloadIsTopologyTemplate(responseWrapper, user, uploadResourceInfo, yamlStringWrapper.getInnerElement()); + } + + } + + protected void handleImport(Wrapper<Response> responseWrapper, User user, UploadResourceInfo resourceInfoObject, String yamlAsString, ResourceAuthorityTypeEnum authority, boolean createNewVersion, String resourceUniqueId) { + Either<ImmutablePair<org.openecomp.sdc.be.model.Resource, ActionStatus>, ResponseFormat> createOrUpdateResponse = null; + Response response = null; + Object representation = null; + + if (CsarValidationUtils.isCsarPayloadName(resourceInfoObject.getPayloadName())) { + log.debug("import resource from csar"); + createOrUpdateResponse = importResourceFromUICsar(resourceInfoObject, user, resourceUniqueId); + } else if (!authority.isUserTypeResource()) { + log.debug("import normative type resource"); + createOrUpdateResponse = resourceImportManager.importNormativeResource(yamlAsString, resourceInfoObject, user, createNewVersion, true); + } else { + log.debug("import user resource (not normative type)"); + createOrUpdateResponse = resourceImportManager.importUserDefinedResource(yamlAsString, resourceInfoObject, user, false, false); + } + if (createOrUpdateResponse.isRight()) { + response = buildErrorResponse(createOrUpdateResponse.right().value()); + } else { + try { + representation = RepresentationUtils.toRepresentation(createOrUpdateResponse.left().value().getLeft()); + } catch (IOException e) { + e.printStackTrace(); + } + ActionStatus successStatus = createOrUpdateResponse.left().value().right; + response = buildOkResponse(getComponentsUtils().getResponseFormat(successStatus), representation); + } + responseWrapper.setInnerElement(response); + } + + private Either<ImmutablePair<org.openecomp.sdc.be.model.Resource, ActionStatus>, ResponseFormat> importResourceFromUICsar(UploadResourceInfo resourceInfoObject, User user, String resourceUniqueId) { + + Either<org.openecomp.sdc.be.model.Resource, ResponseFormat> createOrUpdateResourceRes = null; + ImmutablePair<org.openecomp.sdc.be.model.Resource, ActionStatus> result = null; + ActionStatus actionStatus = null; + org.openecomp.sdc.be.model.Resource resource = new org.openecomp.sdc.be.model.Resource(); + String payloadName = resourceInfoObject.getPayloadName(); + fillResourceFromResourceInfoObject(resource, resourceInfoObject); + + Either<Map<String, byte[]>, ResponseFormat> csarUIPayloadRes = getScarFromPayload(resourceInfoObject); + if (csarUIPayloadRes.isRight()) { + return Either.right(csarUIPayloadRes.right().value()); + } + Map<String, byte[]> csarUIPayload = csarUIPayloadRes.left().value(); + + createOrUpdateResourceRes = getAndValidateCsarYaml(csarUIPayload, resource, user, payloadName); + if (createOrUpdateResourceRes.isRight()) { + return Either.right(createOrUpdateResourceRes.right().value()); + } + if (resourceUniqueId == null || resourceUniqueId.isEmpty()) { + createOrUpdateResourceRes = resourceImportManager.getResourceBusinessLogic().createResource(resource, user, csarUIPayload, payloadName); + if (createOrUpdateResourceRes.isRight()) { + return Either.right(createOrUpdateResourceRes.right().value()); + } + actionStatus = ActionStatus.CREATED; + } else { + createOrUpdateResourceRes = resourceImportManager.getResourceBusinessLogic().validateAndUpdateResourceFromCsar(resource, user, csarUIPayload, payloadName, resourceUniqueId); + if (createOrUpdateResourceRes.isRight()) { + return Either.right(createOrUpdateResourceRes.right().value()); + } + actionStatus = ActionStatus.OK; + } + result = new ImmutablePair<org.openecomp.sdc.be.model.Resource, ActionStatus>(createOrUpdateResourceRes.left().value(), actionStatus); + return Either.left(result); + } + + private Either<org.openecomp.sdc.be.model.Resource, ResponseFormat> getAndValidateCsarYaml(Map<String, byte[]> csarUIPayload, org.openecomp.sdc.be.model.Resource resource, User user, String csarUUID) { + + Either<ImmutablePair<String, String>, ResponseFormat> getToscaYamlRes = CsarValidationUtils.getToscaYaml(csarUIPayload, csarUUID, getComponentsUtils()); + + if (getToscaYamlRes.isRight()) { + ResponseFormat responseFormat = getToscaYamlRes.right().value(); + log.debug("Error when try to get csar toscayamlFile with csar ID {}, error: {}", csarUUID, responseFormat); + BeEcompErrorManager.getInstance().logBeDaoSystemError("Creating resource from CSAR: fetching CSAR with id " + csarUUID + " failed"); + getComponentsUtils().auditResource(responseFormat, user, resource, "", "", AuditingActionEnum.CREATE_RESOURCE, null); + return Either.right(responseFormat); + } + String toscaYaml = getToscaYamlRes.left().value().getValue(); + + log.debug("checking tosca template is valid yml"); + YamlToObjectConverter yamlConvertor = new YamlToObjectConverter(); + boolean isValid = yamlConvertor.isValidYaml(toscaYaml.getBytes()); + if (!isValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_YAML_FILE); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resource.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + return Either.right(responseFormat); + } + + log.debug("checking payload is valid tosca"); + String heatDecodedPayload = (GeneralUtility.isBase64Encoded(toscaYaml)) ? new String(Base64.decodeBase64(toscaYaml)) : toscaYaml; + Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(heatDecodedPayload); + Either<String, ResultStatusEnum> findFirstToscaStringElement = ImportUtils.findFirstToscaStringElement(mappedToscaTemplate, ToscaTagNamesEnum.TOSCA_VERSION); + + if (findFirstToscaStringElement.isRight()) { + isValid = false; + } else { + String defenitionVersionFound = findFirstToscaStringElement.left().value(); + if (defenitionVersionFound == null || defenitionVersionFound.isEmpty()) { + isValid = false; + } else { + isValid = ImportUtils.Constants.TOSCA_DEFINITION_VERSIONS.contains(defenitionVersionFound); + } + } + + if (!isValid) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_TEMPLATE); + EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class); + additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resource.getName()); + getComponentsUtils().auditResource(responseFormat, user, null, "", "", AuditingActionEnum.IMPORT_RESOURCE, additionalParam); + return Either.right(responseFormat); + } + return Either.left(resource); + } + + private void fillResourceFromResourceInfoObject(org.openecomp.sdc.be.model.Resource resource, UploadResourceInfo resourceInfoObject) { + if (resource != null && resourceInfoObject != null) { + resource.setDescription(resourceInfoObject.getDescription()); + resource.setTags(resourceInfoObject.getTags()); + resource.setCategories(resourceInfoObject.getCategories()); + resource.setContactId(resourceInfoObject.getContactId()); + resource.setName(resourceInfoObject.getName()); + resource.setIcon(resourceInfoObject.getResourceIconPath()); + resource.setVendorName(resourceInfoObject.getVendorName()); + resource.setVendorRelease(resourceInfoObject.getVendorRelease()); + resource.setResourceType(ResourceTypeEnum.valueOf(resourceInfoObject.getResourceType())); + List<UploadArtifactInfo> artifactList = resourceInfoObject.getArtifactList(); + if (artifactList != null) { + Map<String, ArtifactDefinition> artifactsHM = new HashMap<String, ArtifactDefinition>(); + for (UploadArtifactInfo artifact : artifactList) { + ArtifactDefinition artifactDef = new ArtifactDefinition(); + artifactDef.setArtifactName(artifact.getArtifactName()); + artifactDef.setArtifactType(artifact.getArtifactType().getType()); + artifactDef.setDescription(artifact.getArtifactDescription()); + artifactDef.setPayloadData(artifact.getArtifactData()); + artifactDef.setArtifactRef(artifact.getArtifactPath()); + artifactsHM.put(artifactDef.getArtifactName(), artifactDef); + } + resource.setArtifacts(artifactsHM); + } + } + + } + + private Either<Map<String, byte[]>, ResponseFormat> getScarFromPayload(UploadResourceInfo innerElement) { + String csarUUID = innerElement.getPayloadName(); + String payloadData = innerElement.getPayloadData(); + if (payloadData == null) { + log.info("Failed to decode received csar", csarUUID); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_NOT_FOUND, csarUUID)); + } + + byte[] decodedPayload = (GeneralUtility.isBase64Encoded(payloadData)) ? Base64.decodeBase64(payloadData.getBytes(StandardCharsets.UTF_8)) : payloadData.getBytes(StandardCharsets.UTF_8); + if (decodedPayload == null) { + log.info("Failed to decode received csar", csarUUID); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_NOT_FOUND, csarUUID)); + } + + Map<String, byte[]> csar = ZipUtil.readZip(decodedPayload); + if (csar == null) { + log.info("Failed to unzip received csar", csarUUID); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID, csarUUID)); + } + return Either.left(csar); + } + + protected void validateInputStream(final HttpServletRequest request, Wrapper<String> dataWrapper, Wrapper<ResponseFormat> errorWrapper) throws IOException { + InputStream inputStream = request.getInputStream(); + byte[] bytes = IOUtils.toByteArray(inputStream); + if (bytes == null || bytes.length == 0) { + log.info("Empty body was sent."); + errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } else { + dataWrapper.setInnerElement(new String(bytes, StandardCharsets.UTF_8)); + } + + } + + protected <T> void validateClassParse(String data, Wrapper<T> parsedClassWrapper, Supplier<Class<T>> classGen, Wrapper<ResponseFormat> errorWrapper) { + try { + T parsedClass = gson.fromJson(data, classGen.get()); + if (parsedClass == null) { + errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } else { + parsedClassWrapper.setInnerElement(parsedClass); + } + } catch (JsonSyntaxException e) { + log.debug("Failed to decode received {} {} to object.", classGen.get().getName(), data, e); + errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + } + + protected void validateComponentInstanceBusinessLogic(HttpServletRequest request, String containerComponentType, Wrapper<ComponentInstanceBusinessLogic> blWrapper, Wrapper<ResponseFormat> errorWrapper) { + ServletContext context = request.getSession().getServletContext(); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } else { + blWrapper.setInnerElement(componentInstanceLogic); + } + } + + protected <T> Response buildResponseFromElement(Wrapper<ResponseFormat> errorWrapper, Wrapper<T> attributeWrapper) throws IOException { + Response response; + if (errorWrapper.isEmpty()) { + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(attributeWrapper.getInnerElement()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } else { + response = buildErrorResponse(errorWrapper.getInnerElement()); + } + return response; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AdditionalInformationServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AdditionalInformationServlet.java new file mode 100644 index 0000000000..aaf8f96dca --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AdditionalInformationServlet.java @@ -0,0 +1,472 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.AdditionalInformationBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.AdditionalInfoParameterInfo; +import org.openecomp.sdc.be.model.AdditionalInformationDefinition; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Additional Information Servlet", description = "Additional Information Servlet") +@Singleton +public class AdditionalInformationServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(AdditionalInformationServlet.class.getName()); + + @POST + @Path("/resources/{resourceId}/additionalinfo") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Additional Information Label and Value", httpMethod = "POST", notes = "Returns created Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Additional information created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response createResourceAdditionalInformationLabel(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "Additional information key value to be created", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return createAdditionalInformationLabelForComponent(NodeTypeEnum.Resource, resourceId, request, userId, data); + + } + + @POST + @Path("/services/{serviceId}/additionalinfo") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Additional Information Label and Value", httpMethod = "POST", notes = "Returns created Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Additional information created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response createServiceAdditionalInformationLabel(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "Additional information key value to be created", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return createAdditionalInformationLabelForComponent(NodeTypeEnum.Service, serviceId, request, userId, data); + + } + + @PUT + @Path("/resources/{resourceId}/additionalinfo/{labelId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Additional Information Label and Value", httpMethod = "PUT", notes = "Returns updated Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Additional information updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response updateResourceAdditionalInformationLabel(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "label id", required = true) @PathParam("labelId") final String labelId, @ApiParam(value = "Additional information key value to be created", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return updateAdditionalInformationLabelForComponent(NodeTypeEnum.Resource, resourceId, labelId, request, userId, data); + + } + + @PUT + @Path("/services/{serviceId}/additionalinfo/{labelId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Additional Information Label and Value", httpMethod = "PUT", notes = "Returns updated Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Additional information updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response updateServiceAdditionalInformationLabel(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "label id", required = true) @PathParam("labelId") final String labelId, @ApiParam(value = "Additional information key value to be created", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return updateAdditionalInformationLabelForComponent(NodeTypeEnum.Service, serviceId, labelId, request, userId, data); + + } + + @DELETE + @Path("/resources/{resourceId}/additionalinfo/{labelId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Additional Information Label and Value", httpMethod = "DELETE", notes = "Returns deleted Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Additional information deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response updateResourceAdditionalInformationLabel(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "label id", required = true) @PathParam("labelId") final String labelId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return deleteAdditionalInformationLabelForComponent(NodeTypeEnum.Resource, resourceId, labelId, request, userId); + + } + + @DELETE + @Path("/services/{serviceId}/additionalinfo/{labelId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Additional Information Label and Value", httpMethod = "DELETE", notes = "Returns deleted Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Additional information deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response deleteServiceAdditionalInformationLabel(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "label id", required = true) @PathParam("labelId") final String labelId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return deleteAdditionalInformationLabelForComponent(NodeTypeEnum.Service, serviceId, labelId, request, userId); + + } + + @GET + @Path("/resources/{resourceId}/additionalinfo/{labelId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Additional Information by id", httpMethod = "GET", notes = "Returns Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "fetched additional information"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response getResourceAdditionalInformationLabel(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "label id", required = true) @PathParam("labelId") final String labelId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getAdditionalInformationLabelForComponent(NodeTypeEnum.Resource, resourceId, labelId, request, userId); + + } + + @GET + @Path("/services/{serviceId}/additionalinfo/{labelId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Additional Information by id", httpMethod = "GET", notes = "Returns Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "fetched additional information"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response getServiceAdditionalInformationLabel(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "label id", required = true) @PathParam("labelId") final String labelId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getAdditionalInformationLabelForComponent(NodeTypeEnum.Service, serviceId, labelId, request, userId); + + } + + @GET + @Path("/resources/{resourceId}/additionalinfo") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get all Additional Information under resource", httpMethod = "GET", notes = "Returns Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "list of additional information"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response getAllResourceAdditionalInformationLabel(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getAllAdditionalInformationLabelForComponent(NodeTypeEnum.Resource, resourceId, request, userId); + + } + + @GET + @Path("/services/{serviceId}/additionalinfo") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get all Additional Information under service", httpMethod = "GET", notes = "Returns Additional Inforamtion property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "list of additional information"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Additional information key already exist") }) + public Response getAllServiceAdditionalInformationLabel(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getAllAdditionalInformationLabelForComponent(NodeTypeEnum.Service, serviceId, request, userId); + + } + + /** + * + * Create additional information property under given resource/service + * + * @param nodeType + * @param uniqueId + * @param request + * @param userId + * @param data + * @return + */ + protected Response createAdditionalInformationLabelForComponent(NodeTypeEnum nodeType, String uniqueId, HttpServletRequest request, String userId, String data) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + log.debug("data is {}", data); + + try { + // convert json to AdditionalInfoParameterInfo + AdditionalInfoParameterInfo additionalInfoParameterInfo = gson.fromJson(data, AdditionalInfoParameterInfo.class); + + // create the new property + AdditionalInformationBusinessLogic businessLogic = getBL(context); + + Either<AdditionalInfoParameterInfo, ResponseFormat> either = businessLogic.createAdditionalInformation(nodeType, uniqueId, additionalInfoParameterInfo, null, userId); + + if (either.isRight()) { + ResponseFormat responseFormat = either.right().value(); + log.info("Failed to create additional information {}. REason - {}", additionalInfoParameterInfo, responseFormat); + return buildErrorResponse(responseFormat); + } + + AdditionalInfoParameterInfo createdAI = either.left().value(); + + log.debug("Additional information {}={} created successfully with id {}", createdAI.getKey(), createdAI.getValue(), createdAI.getUniqueId()); + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); + return buildOkResponse(responseFormat, createdAI); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Additional Information"); + log.debug("Create additional information failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + + } + + /** + * Update additional information property by id under given resource/service + * + * @param nodeType + * @param uniqueId + * @param labelId + * @param request + * @param userId + * @param data + * @return + */ + protected Response updateAdditionalInformationLabelForComponent(NodeTypeEnum nodeType, String uniqueId, String labelId, HttpServletRequest request, String userId, String data) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + log.debug("data is {}", data); + + try { + // convert json to AdditionalInfoParameterInfo + AdditionalInfoParameterInfo additionalInfoParameterInfo = gson.fromJson(data, AdditionalInfoParameterInfo.class); + + // create the new property + AdditionalInformationBusinessLogic businessLogic = getBL(context); + + additionalInfoParameterInfo.setUniqueId(labelId); + + Either<AdditionalInfoParameterInfo, ResponseFormat> either = businessLogic.updateAdditionalInformation(nodeType, uniqueId, additionalInfoParameterInfo, null, userId); + + if (either.isRight()) { + ResponseFormat responseFormat = either.right().value(); + log.info("Failed to update additional information property. Reason - {}", responseFormat); + return buildErrorResponse(responseFormat); + } + + AdditionalInfoParameterInfo createdAI = either.left().value(); + + log.debug("Additional information {}={} updated successfully with id {}", createdAI.getKey(), createdAI.getValue(), createdAI.getUniqueId()); + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, createdAI); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Additional Information"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Additional Information"); + log.debug("Update additional information failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + + } + + /** + * + * Delete an additional information property by id under given resource/service + * + * @param nodeType + * @param uniqueId + * @param labelId + * @param request + * @param userId + * @return + */ + protected Response deleteAdditionalInformationLabelForComponent(NodeTypeEnum nodeType, String uniqueId, String labelId, HttpServletRequest request, String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + try { + + AdditionalInformationBusinessLogic businessLogic = getBL(context); + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(); + additionalInfoParameterInfo.setUniqueId(labelId); + + Either<AdditionalInfoParameterInfo, ResponseFormat> either = businessLogic.deleteAdditionalInformation(nodeType, uniqueId, additionalInfoParameterInfo, null, userId); + + if (either.isRight()) { + ResponseFormat responseFormat = either.right().value(); + log.info("Failed to update additional information property. Reason - {}", responseFormat); + return buildErrorResponse(responseFormat); + } + + AdditionalInfoParameterInfo createdAI = either.left().value(); + + log.debug("Additional information {}={} deleted successfully with id {}", createdAI.getKey(), createdAI.getValue(), createdAI.getUniqueId()); + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, createdAI); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Additional Information"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Additional Information"); + log.debug("Delete additional information failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + + } + + /** + * Get a specific additional information property by a given id under given resource/service + * + * @param nodeType + * @param uniqueId + * @param labelId + * @param request + * @param userId + * @return + */ + protected Response getAdditionalInformationLabelForComponent(NodeTypeEnum nodeType, String uniqueId, String labelId, HttpServletRequest request, String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + try { + + // create the new property + AdditionalInformationBusinessLogic businessLogic = getBL(context); + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(); + additionalInfoParameterInfo.setUniqueId(labelId); + + Either<AdditionalInfoParameterInfo, ResponseFormat> either = businessLogic.getAdditionalInformation(nodeType, uniqueId, additionalInfoParameterInfo, null, userId); + + if (either.isRight()) { + ResponseFormat responseFormat = either.right().value(); + log.info("Failed to update additional information property. Reason - {}", responseFormat); + return buildErrorResponse(responseFormat); + } + + AdditionalInfoParameterInfo createdAI = either.left().value(); + + log.debug("Additional information {}={} fetched successfully with id {}", createdAI.getKey(), createdAI.getValue(), createdAI.getUniqueId()); + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, createdAI); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Additional Information"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Additional Information"); + + log.debug("get additional information failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + + } + + /** + * Get all additional information properties under given resource/service + * + * @param nodeType + * @param uniqueId + * @param request + * @param userId + * @return + */ + protected Response getAllAdditionalInformationLabelForComponent(NodeTypeEnum nodeType, String uniqueId, HttpServletRequest request, String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + try { + + AdditionalInformationBusinessLogic businessLogic = getBL(context); + + Either<AdditionalInformationDefinition, ResponseFormat> either = businessLogic.getAllAdditionalInformation(nodeType, uniqueId, null, userId); + if (either.isRight()) { + ResponseFormat responseFormat = either.right().value(); + log.info("Failed to update additional information property. Reason - {}", responseFormat); + return buildErrorResponse(responseFormat); + } + + AdditionalInformationDefinition additionalInformationDefinition = either.left().value(); + + log.debug("All Additional information retrieved for component {} is {}", uniqueId, additionalInformationDefinition); + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, additionalInformationDefinition); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get All Additional Information"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get All Additional Information"); + log.debug("Get all addiotanl information properties failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + + } + + private AdditionalInformationBusinessLogic getBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + AdditionalInformationBusinessLogic bl = webApplicationContext.getBean(AdditionalInformationBusinessLogic.class); + return bl; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ArtifactServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ArtifactServlet.java new file mode 100644 index 0000000000..b7af00a7d2 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ArtifactServlet.java @@ -0,0 +1,564 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic.ArtifactOperation; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Resource Artifact Servlet", description = "Resource Artifact Servlet") +@Singleton +public class ArtifactServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(ArtifactServlet.class.getName()); + + private Gson gson = new Gson(); + + // *************** Resources + @POST + @Path("/resources/{resourceId}/artifacts") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Artifact", httpMethod = "POST", notes = "Returns created ArtifactDefinition", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Artifact already exist") }) + public Response loadArtifact(@PathParam("resourceId") final String resourceId, @ApiParam(value = "json describe the artifact", required = true) String data, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleUploadRequest(data, request, resourceId, ComponentTypeEnum.RESOURCE); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "loadArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("loadArtifact"); + log.debug("loadArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/resources/{resourceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Artifact", httpMethod = "POST", notes = "Returns updated artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateArtifact(@PathParam("resourceId") final String resourceId, @PathParam("artifactId") final String artifactId, @ApiParam(value = "json describe the artifact", required = true) String data, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleUpdateRequest(data, request, resourceId, artifactId, ComponentTypeEnum.RESOURCE); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "updateArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("updateArtifact"); + log.debug("updateArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @DELETE + @Path("/resources/{resourceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete Artifact", httpMethod = "DELETE", notes = "Returns delete artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response deleteArtifact(@PathParam("resourceId") final String resourceId, @PathParam("artifactId") final String artifactId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDeleteRequest(request, resourceId, artifactId, ComponentTypeEnum.RESOURCE, null, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "deleteArtifact"); + log.debug("deleteArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + // *************** Services + @POST + @Path("/services/{serviceId}/artifacts") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Artifact", httpMethod = "POST", notes = "Returns created ArtifactDefinition", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Artifact already exist") }) + public Response loadInformationArtifact(@PathParam("serviceId") final String serviceId, @ApiParam(value = "json describe the artifact", required = true) String data, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleUploadRequest(data, request, serviceId, ComponentTypeEnum.SERVICE); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "loadInformationArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("loadInformationArtifact"); + log.debug("loadInformationArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/services/{serviceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Artifact", httpMethod = "POST", notes = "Returns updated artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Service artifact created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateInformationArtifact(@PathParam("serviceId") final String serviceId, @PathParam("artifactId") final String artifactId, @ApiParam(value = "json describe the artifact", required = true) String data, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleUpdateRequest(data, request, serviceId, artifactId, ComponentTypeEnum.SERVICE); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "updateInformationArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("updateInformationArtifact"); + log.debug("updateInformationArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + // *************** Services api artifacts + @POST + @Path("/services/{serviceId}/artifacts/api/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Api Artifact", httpMethod = "POST", notes = "Returns created ArtifactDefinition", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Api Artifact Updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateApiArtifact(@PathParam("serviceId") final String serviceId, @PathParam("artifactId") final String artifactId, @ApiParam(value = "json describe the artifact", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam(value = Constants.MD5_HEADER) String origMd5) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleUpdateRequest(data, request, serviceId, artifactId, ComponentTypeEnum.SERVICE); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "updateApiArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("updateApiArtifact"); + log.debug("updateApiArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @DELETE + @Path("/services/{serviceId}/artifacts/api/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete Api Artifact", httpMethod = "DELETE", notes = "Returns Deleted ArtifactDefinition", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "Api Artifact deleted"), @ApiResponse(code = 403, message = "Restricted operation") }) + public Response deleteApiArtifact(@PathParam("serviceId") final String serviceId, @PathParam("artifactId") final String artifactId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @HeaderParam(value = Constants.MD5_HEADER) String origMd5) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDeleteRequest(request, serviceId, artifactId, ComponentTypeEnum.SERVICE, null, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "deleteApiArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("deleteApiArtifact"); + log.debug("deleteApiArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @DELETE + @Path("/services/{serviceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete Artifact", httpMethod = "DELETE", notes = "Returns delete artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Service artifact deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response deleteInformationalArtifact(@PathParam("serviceId") final String serviceId, @PathParam("artifactId") final String artifactId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDeleteRequest(request, serviceId, artifactId, ComponentTypeEnum.SERVICE, null, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "deleteInformationalArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("deleteInformationalArtifact"); + log.debug("deleteInformationalArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + /* + * DOWNLOAD Artifacts by json body in base 64 (because of userId problem with href) + */ + + @GET + @Path("/services/{serviceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Download service Artifact in Base64", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service artifact downloaded"), @ApiResponse(code = 404, message = "Service/Artifact not found") }) + public Response downloadServiceArtifactBase64(@PathParam("serviceId") final String serviceId, @PathParam("artifactId") final String artifactId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDownloadRequest(request, serviceId, artifactId, null, ComponentTypeEnum.SERVICE, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "downloadServiceArtifactBase64"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("downloadServiceArtifactBase64"); + log.debug("downloadServiceArtifactBase64 unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/resources/{resourceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Download resource Artifact in Base64", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource artifact downloaded"), @ApiResponse(code = 404, message = "Resource/Artifact not found") }) + public Response downloadResourceArtifactBase64(@PathParam("resourceId") final String resourceId, @PathParam("artifactId") final String artifactId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDownloadRequest(request, resourceId, artifactId, null, ComponentTypeEnum.RESOURCE, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "downloadResourceArtifactBase64"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("downloadResourceArtifactBase64"); + log.debug("downloadResourceArtifactBase64 unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/{containerComponentType}/{componentId}/resourceInstances/{componentInstanceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Download component Artifact in Base64", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "ResourceInstance artifact downloaded"), @ApiResponse(code = 404, message = "ResourceInstance/Artifact not found") }) + public Response downloadResourceInstanceArtifactBase64( + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, @PathParam("artifactId") final String artifactId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDownloadRequest(request, componentInstanceId, artifactId, componentId, ComponentTypeEnum.RESOURCE_INSTANCE, containerComponentType); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "downloadResourceInstanceArtifactBase64"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("downloadResourceInstanceArtifactBase64"); + log.debug("downloadResourceInstanceArtifactBase64 unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + // *************** Resource lifecycle ( interfces ) + + @POST + @Path("/resources/{resourceId}/{interfaceType}/{operation}/artifacts") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Artifact and Attach to interface", httpMethod = "POST", notes = "Returns created resource", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Artifact already exist") }) + public Response loadArtifactToInterface(@PathParam("resourceId") final String resourceId, @PathParam("interfaceType") final String interfaceType, @PathParam("operation") final String operation, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam(value = Constants.MD5_HEADER) String origMd5, @ApiParam(value = "json describe the artifact", required = true) String data, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleArtifactRequest(data, request, resourceId, interfaceType, operation, null, ComponentTypeEnum.RESOURCE, ArtifactOperation.Create, null, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "loadArtifactToInterface"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("loadArtifactToInterface"); + log.debug("loadArtifactToInterface unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + @DELETE + @Path("/resources/{resourceId}/{interfaceType}/{operation}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "delete Artifact from interface", httpMethod = "delete", notes = "delete matching artifact from interface", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "delete artifact under interface deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Artifact already exist") }) + public Response deleteArtifactToInterface(@PathParam("resourceId") final String resourceId, @PathParam("interfaceType") final String interfaceType, @PathParam("operation") final String operation, @PathParam("artifactId") final String artifactId, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleDeleteRequest(request, resourceId, artifactId, ComponentTypeEnum.RESOURCE, interfaceType, operation); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "deleteArtifactToInterface"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("deleteArtifactToInterface"); + log.debug("deleteArtifactToInterface unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/resources/{resourceId}/{interfaceType}/{operation}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "update Artifact Attach to interface", httpMethod = "post", notes = "updates artifact by interface", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "delete artifact under interface deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Artifact already exist") }) + public Response updateArtifactToInterface(@PathParam("resourceId") final String resourceId, @PathParam("interfaceType") final String interfaceType, @PathParam("operation") final String operation, @PathParam("artifactId") final String artifactId, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam(value = Constants.MD5_HEADER) String origMd5, @Context final HttpServletRequest request, + @ApiParam(value = "json describe the artifact", required = true) String data) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleArtifactRequest(data, request, resourceId, interfaceType, operation, artifactId, ComponentTypeEnum.RESOURCE, ArtifactOperation.Update, null, null); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "updateArtifactToInterface"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("updateArtifactToInterface"); + log.debug("updateArtifactToInterface unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/artifacts/{artifactId}/heatParams") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Instance HEAT_ENV parameters", httpMethod = "POST", notes = "Returns updated artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateRIArtifact( + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, @PathParam("artifactId") final String artifactId, + @ApiParam(value = "json describe the artifact", required = true) String data, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleArtifactRequest(data, request, componentInstanceId, null, null, artifactId, ComponentTypeEnum.RESOURCE_INSTANCE, ArtifactOperation.Update, componentId, containerComponentType); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "updateRIArtifact"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("updateRIArtifact"); + log.debug("updateRIArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Instance artifact payload", httpMethod = "POST", notes = "Returns updated artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateComponentInstanceArtifact(@HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam(value = Constants.MD5_HEADER) String origMd5, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, @PathParam("artifactId") final String artifactId, + @ApiParam(value = "json describe the artifact", required = true) String data, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleArtifactRequest(data, request, componentInstanceId, null, null, artifactId, ComponentTypeEnum.RESOURCE_INSTANCE, ArtifactOperation.Update, componentId, containerComponentType); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "loadResourceInstanceHeatEnvArtifact"); + log.debug("loadResourceInstanceHeatEnvArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/artifacts") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Load Resource Instance artifact payload", httpMethod = "POST", notes = "Returns updated artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response loadComponentInstanceArtifact(@HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam(value = Constants.MD5_HEADER) String origMd5, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, @ApiParam(value = "json describe the artifact", required = true) String data, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + return handleArtifactRequest(data, request, componentInstanceId, null, null, null, ComponentTypeEnum.RESOURCE_INSTANCE, ArtifactOperation.Create, componentId, containerComponentType); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "loadResourceInstanceHeatEnvArtifact"); + log.debug("loadResourceInstanceHeatEnvArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @DELETE + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/artifacts/{artifactId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete Resource Instance artifact", httpMethod = "POST", notes = "Returns deleted artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response deleteComponentInstanceArtifact(@HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam(value = Constants.MD5_HEADER) String origMd5, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, @PathParam("artifactId") final String artifactId, + @ApiParam(value = "json describe the artifact", required = true) String data, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(containerComponentType); + return handleDeleteRequest(request, componentInstanceId, artifactId, ComponentTypeEnum.RESOURCE_INSTANCE, null, null, componentId); + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "deleteArtifact"); + log.debug("deleteArtifact unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + // ////////// API END /////////////////////////// + + // ************ private ********************* + + private Response handleUploadRequest(String data, HttpServletRequest request, String componentId, ComponentTypeEnum componentType) { + return handleArtifactRequest(data, request, componentId, null, componentType, ArtifactOperation.Create); + } + + private Response handleUpdateRequest(String data, HttpServletRequest request, String componentId, String artifactId, ComponentTypeEnum componentType) { + return handleArtifactRequest(data, request, componentId, artifactId, componentType, ArtifactOperation.Update); + } + + private Response handleDownloadRequest(HttpServletRequest request, String componentId, String artifactId, String parentId, ComponentTypeEnum componentType, String containerComponentType) { + String userId = request.getHeader(Constants.USER_ID_HEADER); + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<ImmutablePair<String, byte[]>, ResponseFormat> actionResult = artifactsLogic.handleDownloadRequestById(componentId, artifactId, userId, componentType, parentId, containerComponentType); + + Response response; + if (actionResult.isRight()) { + response = buildErrorResponse(actionResult.right().value()); + } else { + byte[] file = actionResult.left().value().getRight(); + String base64Contents = new String(Base64.encodeBase64(file)); + String artifactName = actionResult.left().value().getLeft(); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + ArtifactUiDownloadData artifactUiDownloadData = new ArtifactUiDownloadData(); + artifactUiDownloadData.setArtifactName(artifactName); + artifactUiDownloadData.setBase64Contents(base64Contents); + response = buildOkResponse(responseFormat, artifactUiDownloadData); + } + return response; + } + + private Response handleDeleteRequest(HttpServletRequest request, String componentId, String artifactId, ComponentTypeEnum componentType, String interfaceType, String operationName) { + return handleDeleteRequest(request, componentId, artifactId, componentType, interfaceType, operationName, null); + } + + private Response handleDeleteRequest(HttpServletRequest request, String componentId, String artifactId, ComponentTypeEnum componentType, String interfaceType, String operationName, String parentId) { + String userId = request.getHeader(Constants.USER_ID_HEADER); + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = artifactsLogic.handleArtifactRequest(componentId, userId, componentType, ArtifactOperation.Delete, artifactId, null, null, null, interfaceType, operationName, + parentId, null); + Response response; + if (actionResult.isRight()) { + response = buildErrorResponse(actionResult.right().value()); + } else { + Either<ArtifactDefinition, Operation> result = actionResult.left().value(); + if (result.isLeft()) { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result.left().value()); + } else { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result.right().value()); + } + } + return response; + + } + + private Response handleArtifactRequest(String data, HttpServletRequest request, String componentId, String interfaceName, String operationName, String artifactId, ComponentTypeEnum componentType, ArtifactOperation operation, String parentId, + String containerComponentType) { + ArtifactDefinition artifactInfo = RepresentationUtils.convertJsonToArtifactDefinition(data, ArtifactDefinition.class); + String origMd5 = request.getHeader(Constants.MD5_HEADER); + + String userId = request.getHeader(Constants.USER_ID_HEADER); + + ServletContext context = request.getSession().getServletContext(); + ArtifactsBusinessLogic artifactsLogic = getArtifactBL(context); + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> actionResult = artifactsLogic.handleArtifactRequest(componentId, userId, componentType, operation, artifactId, artifactInfo, origMd5, data, interfaceName, operationName, parentId, + containerComponentType); + Response response; + if (actionResult.isRight()) { + response = buildErrorResponse(actionResult.right().value()); + } else { + Either<ArtifactDefinition, Operation> result = actionResult.left().value(); + if (result.isLeft()) { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result.left().value()); + } else { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result.right().value()); + } + } + return response; + + } + + private Response handleArtifactRequest(String data, HttpServletRequest request, String componentId, String artifactId, ComponentTypeEnum componentType, ArtifactOperation operation) { + return handleArtifactRequest(data, servletRequest, componentId, null, null, artifactId, componentType, operation, null, null); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java new file mode 100644 index 0000000000..b5e64ae00e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java @@ -0,0 +1,278 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.AttributeBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.AttributeDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +/** + * Web Servlet for actions on Attributes + * + * @author mshitrit + * + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Resource Attribute Servlet", description = "Resource Attribute Servlet") +@Singleton +public class AttributeServlet extends AbstractValidationsServlet { + private static Logger log = LoggerFactory.getLogger(AttributeServlet.class.getName()); + + /** + * Creates new Attribute on a resource with given resource ID + * + * @param resourceId + * @param data + * @param request + * @param userId + * @return + */ + @POST + @Path("resources/{resourceId}/attributes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource Attribute", httpMethod = "POST", notes = "Returns created resource attribute", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Resource attribute already exist") }) + public Response createAttribute(@ApiParam(value = "resource id to update with new attribute", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "Resource attribute to be created", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + log.debug("data is {}", data); + + try { + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Wrapper<AttributeDefinition> attributesWrapper = new Wrapper<>(); + // convert json to AttributeDefinition + + buildAttributeFromString(data, attributesWrapper, errorWrapper); + if (errorWrapper.isEmpty()) { + AttributeBusinessLogic businessLogic = getBusinessLogic(context, () -> AttributeBusinessLogic.class); + Either<AttributeDefinition, ResponseFormat> createAttribute = businessLogic.createAttribute(resourceId, attributesWrapper.getInnerElement(), userId); + if (createAttribute.isRight()) { + errorWrapper.setInnerElement(createAttribute.right().value()); + } else { + attributesWrapper.setInnerElement(createAttribute.left().value()); + } + } + + Response response; + if (!errorWrapper.isEmpty()) { + log.info("Failed to create Attribute. Reason - ", errorWrapper.getInnerElement()); + response = buildErrorResponse(errorWrapper.getInnerElement()); + } else { + AttributeDefinition createdAttDef = attributesWrapper.getInnerElement(); + log.debug("Attribute {} created successfully with id {}", createdAttDef.getName(), createdAttDef.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); + response = buildOkResponse(responseFormat, RepresentationUtils.toRepresentation(createdAttDef)); + } + + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Attribute"); + log.debug("create property failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + /** + * Updates existing Attribute with given attributeID on a resource with given resourceID + * + * @param resourceId + * @param attributeId + * @param data + * @param request + * @param userId + * @return + */ + @PUT + @Path("resources/{resourceId}/attributes/{attributeId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Attribute", httpMethod = "PUT", notes = "Returns updated attribute", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource attribute updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateAttribute(@ApiParam(value = "resource id to update with new attribute", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "attribute id to update", required = true) @PathParam("attributeId") final String attributeId, @ApiParam(value = "Resource attribute to update", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + try { + // convert json to PropertyDefinition + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Wrapper<AttributeDefinition> attributesWrapper = new Wrapper<>(); + // convert json to AttributeDefinition + + buildAttributeFromString(data, attributesWrapper, errorWrapper); + + if (errorWrapper.isEmpty()) { + AttributeBusinessLogic businessLogic = getBusinessLogic(context, () -> AttributeBusinessLogic.class); + Either<AttributeDefinition, ResponseFormat> eitherUpdateAttribute = businessLogic.updateAttribute(resourceId, attributeId, attributesWrapper.getInnerElement(), userId); + // update property + if (eitherUpdateAttribute.isRight()) { + errorWrapper.setInnerElement(eitherUpdateAttribute.right().value()); + } else { + attributesWrapper.setInnerElement(eitherUpdateAttribute.left().value()); + } + } + + Response response; + if (!errorWrapper.isEmpty()) { + log.info("Failed to update Attribute. Reason - ", errorWrapper.getInnerElement()); + response = buildErrorResponse(errorWrapper.getInnerElement()); + } else { + AttributeDefinition updatedAttribute = attributesWrapper.getInnerElement(); + log.debug("Attribute id {} updated successfully ", updatedAttribute.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + response = buildOkResponse(responseFormat, RepresentationUtils.toRepresentation(updatedAttribute)); + } + + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Attribute"); + log.debug("update attribute failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + /** + * Deletes existing Attribute with given attributeID on a resource with given resourceID + * + * @param resourceId + * @param attributeId + * @param request + * @param userId + * @return + */ + @DELETE + @Path("resources/{resourceId}/attributes/{attributeId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource Attribute", httpMethod = "DELETE", notes = "Returns deleted attribute", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted attribute"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Resource property not found") }) + public Response deleteAttribute(@ApiParam(value = "resource id of attribute", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "Attribute id to delete", required = true) @PathParam("attributeId") final String attributeId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + try { + + // delete the property + AttributeBusinessLogic businessLogic = getBusinessLogic(context, () -> AttributeBusinessLogic.class); + Either<AttributeDefinition, ResponseFormat> eitherAttribute = businessLogic.deleteAttribute(resourceId, attributeId, userId); + if (eitherAttribute.isRight()) { + log.debug("Failed to delete Attribute. Reason - ", eitherAttribute.right().value()); + return buildErrorResponse(eitherAttribute.right().value()); + } + AttributeDefinition attributeDefinition = eitherAttribute.left().value(); + String name = attributeDefinition.getName(); + + log.debug("Attribute {} deleted successfully with id {}", name, attributeDefinition.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); + return buildOkResponse(responseFormat, RepresentationUtils.toRepresentation(attributeDefinition)); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Attribute"); + log.debug("delete attribute failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + private void buildAttributeFromString(String data, Wrapper<AttributeDefinition> attributesWrapper, Wrapper<ResponseFormat> errorWrapper) { + + try { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + final AttributeDefinition attribute = gson.fromJson(data, AttributeDefinition.class); + if (attribute == null) { + log.info("Attribute content is invalid - {}", data); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + errorWrapper.setInnerElement(responseFormat); + } else { + attributesWrapper.setInnerElement(attribute); + } + + } catch (Exception e) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + errorWrapper.setInnerElement(responseFormat); + log.debug("Attribute content is invalid - {}", data, e); + log.info("Attribute content is invalid - {}", data); + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java new file mode 100644 index 0000000000..f21b57f6fb --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -0,0 +1,226 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Supplier; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + +import org.openecomp.sdc.be.components.clean.ComponentsCleanBusinessLogic; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ElementBusinessLogic; +import org.openecomp.sdc.be.components.impl.GroupBusinessLogic; +import org.openecomp.sdc.be.components.impl.MonitoringBusinessLogic; +import org.openecomp.sdc.be.components.impl.ProductBusinessLogic; +import org.openecomp.sdc.be.components.impl.ProductComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.components.impl.VFComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.IElementDAO; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.servlets.BasicServlet; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +public class BeGenericServlet extends BasicServlet { + + @Context + protected HttpServletRequest servletRequest; + + private static Logger log = LoggerFactory.getLogger(BeGenericServlet.class.getName()); + + /******************** New error response mechanism **************/ + + protected Response buildErrorResponse(ResponseFormat requestErrorWrapper) { + Response response = Response.status(requestErrorWrapper.getStatus()).entity(gson.toJson(requestErrorWrapper.getRequestError())).build(); + return response; + } + + protected Response buildOkResponse(ResponseFormat errorResponseWrapper, Object entity) { + return buildOkResponse(errorResponseWrapper, entity, null); + } + + protected Response buildOkResponse(ResponseFormat errorResponseWrapper, Object entity, Map<String, String> additionalHeaders) { + int status = errorResponseWrapper.getStatus(); + ResponseBuilder responseBuilder = Response.status(status); + if (entity != null) { + if (log.isTraceEnabled()) + log.trace("returned entity is {}", entity.toString()); + responseBuilder = responseBuilder.entity(entity); + } + if (additionalHeaders != null) { + for (Entry<String, String> additionalHeader : additionalHeaders.entrySet()) { + String headerName = additionalHeader.getKey(); + String headerValue = additionalHeader.getValue(); + if (log.isTraceEnabled()) + log.trace("Adding header {} with value {} to the response", headerName, headerValue); + responseBuilder.header(headerName, headerValue); + } + } + return responseBuilder.build(); + } + + /*******************************************************************************************************/ + + protected UserBusinessLogic getUserAdminManager(ServletContext context) { + return getBusinessLogic(context, () -> UserBusinessLogic.class); + } + + protected ResourceBusinessLogic getResourceBL(ServletContext context) { + return getBusinessLogic(context, () -> ResourceBusinessLogic.class); + } + + protected ComponentsCleanBusinessLogic getComponentCleanerBL(ServletContext context) { + return getBusinessLogic(context, () -> ComponentsCleanBusinessLogic.class); + } + + protected ServiceBusinessLogic getServiceBL(ServletContext context) { + return getBusinessLogic(context, () -> ServiceBusinessLogic.class); + } + + protected ProductBusinessLogic getProductBL(ServletContext context) { + return getBusinessLogic(context, () -> ProductBusinessLogic.class); + } + + protected ArtifactsBusinessLogic getArtifactBL(ServletContext context) { + return getBusinessLogic(context, () -> ArtifactsBusinessLogic.class); + } + + protected ElementBusinessLogic getElementBL(ServletContext context) { + return getBusinessLogic(context, () -> ElementBusinessLogic.class); + } + + protected MonitoringBusinessLogic getMonitoringBL(ServletContext context) { + return getBusinessLogic(context, () -> MonitoringBusinessLogic.class); + } + + protected <SomeBusinessLogic> SomeBusinessLogic getBusinessLogic(ServletContext context, Supplier<Class<SomeBusinessLogic>> businessLogicClassGen) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + SomeBusinessLogic monitoringBusinessLogic = webApplicationContext.getBean(businessLogicClassGen.get()); + return monitoringBusinessLogic; + } + + protected GroupBusinessLogic getGroupBL(ServletContext context) { + + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + GroupBusinessLogic groupBusinessLogic = webApplicationContext.getBean(GroupBusinessLogic.class); + return groupBusinessLogic; + } + + protected ComponentInstanceBusinessLogic getComponentInstanceBL(ServletContext context, ComponentTypeEnum containerComponentType) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + if (containerComponentType == ComponentTypeEnum.RESOURCE) { + return webApplicationContext.getBean(VFComponentInstanceBusinessLogic.class); + } + if (containerComponentType == ComponentTypeEnum.SERVICE) { + return webApplicationContext.getBean(ServiceComponentInstanceBusinessLogic.class); + } + if (containerComponentType == ComponentTypeEnum.PRODUCT) { + return webApplicationContext.getBean(ProductComponentInstanceBusinessLogic.class); + } + return null; + } + + protected IElementDAO getElementDao(Class<? extends IElementDAO> clazz, ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + + return webApplicationContext.getBean(clazz); + } + + protected ComponentsUtils getComponentsUtils() { + ServletContext context = this.servletRequest.getSession().getServletContext(); + + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + ComponentsUtils componentsUtils = webApplicationContext.getBean(ComponentsUtils.class); + return componentsUtils; + } + + /** + * Used to support Unit Test.<br> + * Header Params are not supported in Unit Tests + * + * @return + */ + protected String initHeaderParam(String headerValue, HttpServletRequest request, String headerName) { + String retValue; + if (headerValue != null) { + retValue = headerValue; + } else { + retValue = request.getHeader(headerName); + } + return retValue; + } + + protected String getContentDispositionValue(String artifactFileName) { + return new StringBuilder().append("attachment; filename=\"").append(artifactFileName).append("\"").toString(); + } + + protected ComponentBusinessLogic getComponentBL(ComponentTypeEnum componentTypeEnum, ServletContext context) { + ComponentBusinessLogic businessLogic; + switch (componentTypeEnum) { + case RESOURCE: { + businessLogic = getResourceBL(context); + break; + } + case SERVICE: { + businessLogic = getServiceBL(context); + break; + } + case PRODUCT: { + businessLogic = getProductBL(context); + break; + } + case RESOURCE_INSTANCE: { + businessLogic = getResourceBL(context); + break; + } + default: { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "getComponentBL"); + BeEcompErrorManager.getInstance().logBeSystemError("getComponentBL"); + throw new IllegalArgumentException("Illegal component type:" + componentTypeEnum.getValue()); + } + } + return businessLogic; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeMonitoringServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeMonitoringServlet.java new file mode 100644 index 0000000000..ffcd9c68fc --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeMonitoringServlet.java @@ -0,0 +1,203 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.List; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.DistributionMonitoringBusinessLogic; +import org.openecomp.sdc.be.components.impl.HealthCheckBusinessLogic; +import org.openecomp.sdc.be.components.impl.MonitoringBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.api.HealthCheckInfo; +import org.openecomp.sdc.common.api.HealthCheckWrapper; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckComponent; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.monitoring.MonitoringEvent; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.TRACE, trim = false) +@Path("/") +@Api(value = "BE Monitoring", description = "BE Monitoring") +@Singleton +public class BeMonitoringServlet extends BeGenericServlet { + + Gson prettyGson = new GsonBuilder().setPrettyPrinting().create(); + + private static Logger log = LoggerFactory.getLogger(ConfigServlet.class.getName()); + + @GET + @Path("/healthCheck") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "return aggregate BE health check of Titan, ES and BE", notes = "return BE health check", response = String.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Titan, ES and BE are all up"), @ApiResponse(code = 500, message = "One or more BE components (Titan, ES, BE) are down") }) + public Response getHealthCheck(@Context final HttpServletRequest request) { + try { + HealthCheckBusinessLogic healthCheckBusinessLogic = getHealthCheckBL(request.getSession().getServletContext()); + List<HealthCheckInfo> beHealthCheckInfos = healthCheckBusinessLogic.getBeHealthCheckInfosStatus(); + + // List<HealthCheckInfo> beHealthCheckInfos = + // HealthCheckBusinessLogic.getInstance().getBeHealthCheckInfos(request.getSession().getServletContext()); + ActionStatus status = getAggregateBeStatus(beHealthCheckInfos); + String sdcVersion = getVersionFromContext(request); + if (sdcVersion == null || sdcVersion.isEmpty()) { + sdcVersion = "UNKNOWN"; + } + String siteMode = healthCheckBusinessLogic.getSiteMode(); + HealthCheckWrapper healthCheck = new HealthCheckWrapper(beHealthCheckInfos, sdcVersion, siteMode); + // The response can be either with 200 or 500 aggregate status - the + // body of individual statuses is returned either way + + String healthCheckStr = prettyGson.toJson(healthCheck); + return buildOkResponse(getComponentsUtils().getResponseFormat(status), healthCheckStr); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeHealthCheckError, "BeHealthCheck"); + BeEcompErrorManager.getInstance().logBeHealthCheckError("BeHealthCheck"); + log.debug("BE health check unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/monitoring") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response processMonitoringMetrics(@Context final HttpServletRequest request, String json) { + try { + MonitoringEvent monitoringEvent = convertContentToJson(json, MonitoringEvent.class); + if (monitoringEvent == null) { + return buildErrorResponse(getComponentsUtils().getResponseFormatAdditionalProperty(ActionStatus.GENERAL_ERROR)); + } + log.trace("Received monitoring metrics: {}", monitoringEvent.toString()); + ServletContext context = request.getSession().getServletContext(); + MonitoringBusinessLogic bl = getMonitoringBL(context); + Either<Boolean, ResponseFormat> result = bl.logMonitoringEvent(monitoringEvent); + if (result.isRight()) { + return buildErrorResponse(result.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), null); + + } catch (Exception e) { + log.debug("BE system metrics unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormatAdditionalProperty(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/version") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "return the ASDC application version", notes = "return the SDC application version", response = String.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "return SDC version"), @ApiResponse(code = 500, message = "Internal Error") }) + public Response getSdcVersion(@Context final HttpServletRequest request) { + try { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + String version = getVersionFromContext(request); + log.debug("sdc version from manifest is: {}", version); + if (version == null || version.isEmpty()) { + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.SDC_VERSION_NOT_FOUND)); + } + + HealthCheckInfo versionInfo = new HealthCheckInfo(); + versionInfo.setVersion(version); + + // The response can be either with 200 or 500 aggregate status - the + // body of individual statuses is returned either way + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), versionInfo); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "getSDCVersion"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("getSDCVersion"); + log.debug("BE get SDC version unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private String getVersionFromContext(HttpServletRequest request) { + ServletContext servletContext = request.getSession().getServletContext(); + String version = (String) servletContext.getAttribute(Constants.SDC_RELEASE_VERSION_ATTR); + return version; + } + + private ActionStatus getAggregateBeStatus(List<HealthCheckInfo> beHealthCheckInfos) { + ActionStatus status = ActionStatus.OK; + for (HealthCheckInfo healthCheckInfo : beHealthCheckInfos) { + if (healthCheckInfo.getHealthCheckStatus().equals(HealthCheckStatus.DOWN) && healthCheckInfo.getHealthCheckComponent() != HealthCheckComponent.DE) { + status = ActionStatus.GENERAL_ERROR; + break; + } + } + return status; + } + + protected MonitoringEvent convertContentToJson(String content, Class<MonitoringEvent> clazz) { + + MonitoringEvent object = null; + try { + object = gson.fromJson(content, clazz); + object.setFields(null); + } catch (Exception e) { + log.debug("Failed to convert the content {} to object. {}", content.substring(0, Math.min(50, content.length())), e); + } + + return object; + } + + private HealthCheckBusinessLogic getHealthCheckBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + HealthCheckBusinessLogic healthCheckBl = webApplicationContext.getBean(HealthCheckBusinessLogic.class); + return healthCheckBl; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java new file mode 100644 index 0000000000..4e6d0bcd7f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java @@ -0,0 +1,744 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.commons.io.IOUtils; +import org.codehaus.jackson.map.ObjectMapper; +import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.info.CreateAndAssotiateInfo; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceAttribute; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Resource Instance Servlet", description = "Resource Instance Servlet") +@Singleton +public class ComponentInstanceServlet extends AbstractValidationsServlet { + + private static Logger log = LoggerFactory.getLogger(ComponentInstanceServlet.class.getName()); + + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create(); + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create ComponentInstance", httpMethod = "POST", notes = "Returns created ComponentInstance", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Component created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Component instance already exist") }) + public Response createComponentInstance(@ApiParam(value = "RI object to be created", required = true) String data, @PathParam("componentId") final String containerComponentId, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @HeaderParam(value = Constants.USER_ID_HEADER) @ApiParam(value = "USER_ID of modifier user", required = true) String userId, @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + + try { + + ComponentInstance componentInstance = RepresentationUtils.fromRepresentation(data, ComponentInstance.class); + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceLogic.createComponentInstance(containerComponentType, containerComponentId, userId, componentInstance); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Component Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Component Instance"); + log.debug("create component instance failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update resource instance", httpMethod = "POST", notes = "Returns updated resource instance", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource instance updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateComponentInstance(@PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, + @ApiParam(value = "valid values: resources / services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + + log.debug("Start handle request of {}", url); + + InputStream inputStream = request.getInputStream(); + + byte[] bytes = IOUtils.toByteArray(inputStream); + + if (bytes == null || bytes.length == 0) { + log.info("Empty body was sent."); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + String userId = request.getHeader(Constants.USER_ID_HEADER); + + String data = new String(bytes); + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + Either<ComponentInstance, ResponseFormat> convertResponse = convertToResourceInstance(data); + + if (convertResponse.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Resource Instance - updateResourceInstance"); + BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - updateResourceInstance"); + log.debug("Failed to convert received data to BE format."); + return buildErrorResponse(convertResponse.right().value()); + } + + ComponentInstance resourceInstance = convertResponse.left().value(); + Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceLogic.updateComponentInstance(containerComponentType, componentId, componentInstanceId, userId, resourceInstance); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Resource Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource Instance"); + log.debug("update resource instance with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + // TODO Tal New Multiple Instance API + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/multipleComponentInstance") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update resource instance multiple component", httpMethod = "POST", notes = "Returns updated resource instance", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource instance updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateMultipleComponentInstance(@PathParam("componentId") final String componentId, + @ApiParam(value = "valid values: resources / services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @Context final HttpServletRequest request, @ApiParam(value = "Component Instance JSON Array", required = true) final String componentInstanceJsonArray) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + try { + log.debug("Start handle request of {}", url); + + if (componentInstanceJsonArray == null || componentInstanceJsonArray.length() == 0) { + log.info("Empty JSON list was sent."); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + String userId = request.getHeader(Constants.USER_ID_HEADER); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<List<ComponentInstance>, ResponseFormat> convertResponse = convertToMultipleResourceInstance(componentInstanceJsonArray); + + if (convertResponse.isRight()) { + // Using both ECOMP error methods, show to Sofer + BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - updateResourceInstance"); + /* + * BeEcompErrorManager.getInstance().processEcompError( EcompErrorName.BeSystemError, "Resource Instance - updateResourceInstance"); + */ + log.debug("Failed to convert received data to BE format."); + return buildErrorResponse(convertResponse.right().value()); + } + + List<ComponentInstance> componentInstanceList = convertResponse.left().value(); + + Either<List<ComponentInstance>, ResponseFormat> actionResponse = componentInstanceLogic.updateComponentInstance(containerComponentType, componentId, userId, componentInstanceList, true, true); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Exception e) { + /* + * BeEcompErrorManager.getInstance().processEcompError( EcompErrorName.BeRestApiGeneralError, "Update Resource Instance" ); + */ + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource Instance"); + log.debug("update resource instance with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + @DELETE + @Path("/{containerComponentType}/{componentId}/resourceInstance/{resourceInstanceId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete ResourceInstance", httpMethod = "DELETE", notes = "Returns delete resourceInstance", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "ResourceInstance deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response deleteResourceInstance(@PathParam("componentId") final String componentId, @PathParam("resourceInstanceId") final String resourceInstanceId, + @ApiParam(value = "valid values: resources / services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + Response response = null; + try { + log.debug("Start handle request of {}", url); + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + String userId = request.getHeader(Constants.USER_ID_HEADER); + Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceLogic.deleteComponentInstance(containerComponentType, componentId, resourceInstanceId, userId); + + if (actionResponse.isRight()) { + response = buildErrorResponse(actionResponse.right().value()); + } else { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null); + } + return response; + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Resource Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Resource Instance"); + log.debug("delete resource instance with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @ApiParam(value = "allowed values are resources /services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/associate") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Associate RI to RI", httpMethod = "POST", notes = "Returns created RelationshipInfo", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Relationship created"), @ApiResponse(code = 403, message = "Missing information"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Relationship already exist") }) + public Response associateRIToRI(@ApiParam(value = "unique id of the container component") @PathParam("componentId") final String componentId, + @ApiParam(value = "allowed values are resources /services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) @PathParam("containerComponentType") final String containerComponentType, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "RelationshipInfo", required = true) String data, @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + Response response = null; + + try { + + log.debug("Start handle request of {}", url); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<RequirementCapabilityRelDef, ResponseFormat> regInfoW = convertToRequirementCapabilityRelDef(data); + + Either<RequirementCapabilityRelDef, ResponseFormat> resultOp; + if (regInfoW.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Resource Instance - associateRIToRI"); + BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - associateRIToRI"); + log.debug("Failed to convert received data to BE format."); + resultOp = Either.right(regInfoW.right().value()); + } else { + RequirementCapabilityRelDef requirementDef = regInfoW.left().value(); + resultOp = componentInstanceLogic.associateRIToRI(componentId, userId, requirementDef, componentTypeEnum); + } + + Either<RequirementCapabilityRelDef, ResponseFormat> actionResponse = resultOp; + + if (actionResponse.isRight()) { + response = buildErrorResponse(actionResponse.right().value()); + } else { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + } + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Associate Resource Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Associate Resource Instance"); + log.debug("associate resource instance to another RI with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @PUT + @Path("/{containerComponentType}/{componentId}/resourceInstance/dissociate") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Dissociate RI from RI", httpMethod = "PUT", notes = "Returns deleted RelationshipInfo", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Relationship deleted"), @ApiResponse(code = 403, message = "Missing information"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response dissociateRIFromRI( + @ApiParam(value = "allowed values are resources /services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) @PathParam("containerComponentType") final String containerComponentType, + @ApiParam(value = "unique id of the container component") @PathParam("componentId") final String componentId, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "RelationshipInfo", required = true) String data, + @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + try { + + log.debug("Start handle request of {}", url); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<RequirementCapabilityRelDef, ResponseFormat> regInfoW = convertToRequirementCapabilityRelDef(data); + if (regInfoW.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Resource Instance - dissociateRIFromRI"); + BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - dissociateRIFromRI"); + log.debug("Failed to convert received data to BE format."); + return buildErrorResponse(regInfoW.right().value()); + } + + RequirementCapabilityRelDef requirementDef = regInfoW.left().value(); + Either<RequirementCapabilityRelDef, ResponseFormat> actionResponse = componentInstanceLogic.dissociateRIFromRI(componentId, userId, requirementDef, componentTypeEnum); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Dissociate Resource Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Dissociate Resource Instance"); + log.debug("dissociate resource instance from service failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/createAndAssociate") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create RI and associate RI to RI", httpMethod = "POST", notes = "Returns created RI and RelationshipInfo", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "RI created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Relationship already exist") }) + public Response createAndAssociateRIToRI(@PathParam("componentId") final String componentId, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + + log.debug("Start handle request of {}", url); + + InputStream inputStream = request.getInputStream(); + + byte[] bytes = IOUtils.toByteArray(inputStream); + + if (bytes == null || bytes.length == 0) { + log.info("Empty body was sent."); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + String userId = request.getHeader(Constants.USER_ID_HEADER); + + String data = new String(bytes); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<CreateAndAssotiateInfo, ActionStatus> convertStatus = convertJsonToObject(data, CreateAndAssotiateInfo.class); + if (convertStatus.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Resource Instance - createAndAssociateRIToRI"); + BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - createAndAssociateRIToRI"); + log.debug("Failed to convert received data to BE format."); + Either<Object, ResponseFormat> formattedResponse = Either.right(getComponentsUtils().getResponseFormat(convertStatus.right().value())); + return buildErrorResponse(formattedResponse.right().value()); + } + + CreateAndAssotiateInfo createAndAssotiateInfo = convertStatus.left().value(); + Either<CreateAndAssotiateInfo, ResponseFormat> actionResponse = componentInstanceLogic.createAndAssociateRIToRI(containerComponentType, componentId, userId, createAndAssotiateInfo); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value()); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create and Associate Resource Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create and Associate Resource Instance"); + log.debug("create and associate RI failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/property") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update resource instance property", httpMethod = "POST", notes = "Returns updated resource instance property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource instance created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateResourceInstanceProperty(@ApiParam(value = "service id") @PathParam("componentId") final String componentId, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @ApiParam(value = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId, @ApiParam(value = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + try { + Wrapper<String> dataWrapper = new Wrapper<>(); + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Wrapper<ComponentInstanceProperty> propertyWrapper = new Wrapper<>(); + + validateInputStream(request, dataWrapper, errorWrapper); + + if (errorWrapper.isEmpty()) { + validateClassParse(dataWrapper.getInnerElement(), propertyWrapper, () -> ComponentInstanceProperty.class, errorWrapper); + } + + if (!errorWrapper.isEmpty()) { + return buildErrorResponse(errorWrapper.getInnerElement()); + } + + ComponentInstanceProperty property = propertyWrapper.getInnerElement(); + + log.debug("Start handle request of updateResourceInstanceProperty. Received property is {}", property); + + ServletContext context = request.getSession().getServletContext(); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<ComponentInstanceProperty, ResponseFormat> actionResponse = componentInstanceLogic.createOrUpdatePropertyValue(componentTypeEnum, componentId, componentInstanceId, property, userId); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + + ComponentInstanceProperty resourceInstanceProperty = actionResponse.left().value(); + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(resourceInstanceProperty); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + log.error("create and associate RI failed with exception: ", e.getMessage()); + log.debug("create and associate RI failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + /** + * Updates ResourceInstance Attribute + * + * @param componentId + * @param containerComponentType + * @param componentInstanceId + * @param userId + * @param request + * @return + */ + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/attribute") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update resource instance attribute", httpMethod = "POST", notes = "Returns updated resource instance attribute", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource instance created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateResourceInstanceAttribute(@ApiParam(value = "service id") @PathParam("componentId") final String componentId, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @ApiParam(value = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId, @ApiParam(value = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + try { + + Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + Wrapper<String> dataWrapper = new Wrapper<>(); + Wrapper<ComponentInstanceAttribute> attributeWrapper = new Wrapper<>(); + Wrapper<ComponentInstanceBusinessLogic> blWrapper = new Wrapper<>(); + + validateInputStream(request, dataWrapper, errorWrapper); + + if (errorWrapper.isEmpty()) { + validateClassParse(dataWrapper.getInnerElement(), attributeWrapper, () -> ComponentInstanceAttribute.class, errorWrapper); + } + + if (errorWrapper.isEmpty()) { + validateComponentInstanceBusinessLogic(request, containerComponentType, blWrapper, errorWrapper); + } + + if (errorWrapper.isEmpty()) { + ComponentInstanceBusinessLogic componentInstanceLogic = blWrapper.getInnerElement(); + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + log.debug("Start handle request of ComponentInstanceAttribute. Received attribute is {}", attributeWrapper.getInnerElement()); + Either<ComponentInstanceAttribute, ResponseFormat> eitherAttribute = componentInstanceLogic.createOrUpdateAttributeValue(componentTypeEnum, componentId, componentInstanceId, attributeWrapper.getInnerElement(), userId); + if (eitherAttribute.isRight()) { + errorWrapper.setInnerElement(eitherAttribute.right().value()); + } else { + attributeWrapper.setInnerElement(eitherAttribute.left().value()); + } + } + + return buildResponseFromElement(errorWrapper, attributeWrapper); + + } catch (Exception e) { + log.error("create and associate RI failed with exception: ", e.getMessage()); + log.debug("create and associate RI failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + @DELETE + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/property/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update resource instance", httpMethod = "DELETE", notes = "Returns deleted resource instance property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource instance created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response deleteResourceInstanceProperty(@ApiParam(value = "service id") @PathParam("componentId") final String componentId, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @ApiParam(value = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId, @ApiParam(value = "property id") @PathParam("propertyId") final String propertyId, + @ApiParam(value = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @Context final HttpServletRequest request) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<ComponentInstanceProperty, ResponseFormat> actionResponse = componentInstanceLogic.deletePropertyValue(componentTypeEnum, componentId, componentInstanceId, propertyId, userId); + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null); + } catch (Exception e) { + log.error("create and associate RI failed with exception: ", e.getMessage()); + log.debug("create and associate RI failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + @POST + @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/changeVersion") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update resource instance", httpMethod = "POST", notes = "Returns updated resource instance", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource instance created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response changeResourceInstanceVersion(@PathParam("componentId") final String componentId, @PathParam("componentInstanceId") final String componentInstanceId, + @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("containerComponentType") final String containerComponentType, + @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + try { + + log.debug("Start handle request of {}", url); + + InputStream inputStream = request.getInputStream(); + + byte[] bytes = IOUtils.toByteArray(inputStream); + + if (bytes == null || bytes.length == 0) { + log.info("Empty body was sent."); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + String userId = request.getHeader(Constants.USER_ID_HEADER); + + String data = new String(bytes); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + ComponentInstanceBusinessLogic componentInstanceLogic = getComponentInstanceBL(context, componentTypeEnum); + if (componentInstanceLogic == null) { + log.debug("Unsupported component type {}", containerComponentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType)); + } + + Either<ComponentInstance, ResponseFormat> convertResponse = convertToResourceInstance(data); + + if (convertResponse.isRight()) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Resource Instance - updateResourceInstance"); + BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - updateResourceInstance"); + log.debug("Failed to convert received data to BE format."); + return buildErrorResponse(convertResponse.right().value()); + } + + ComponentInstance newResourceInstance = convertResponse.left().value(); + Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceLogic.changeComponentInstanceVersion(containerComponentType, componentId, componentInstanceId, userId, newResourceInstance); + + if (actionResponse.isRight()) { + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Resource Instance"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource Instance"); + log.debug("update resource instance with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + private Either<ComponentInstance, ResponseFormat> convertToResourceInstance(String data) { + + // Either<ComponentInstance, ActionStatus> convertStatus = + // convertJsonToObject(data, ComponentInstance.class); + Either<ComponentInstance, ResponseFormat> convertStatus = getComponentsUtils().convertJsonToObjectUsingObjectMapper(data, new User(), ComponentInstance.class, null, ComponentTypeEnum.RESOURCE_INSTANCE); + if (convertStatus.isRight()) { + return Either.right(convertStatus.right().value()); + } + ComponentInstance resourceInstanceInfo = convertStatus.left().value(); + + return Either.left(resourceInstanceInfo); + } + + // TODO Tal New API for Multiple Items move on canvas + private Either<List<ComponentInstance>, ResponseFormat> convertToMultipleResourceInstance(String dataList) { + + Either<ComponentInstance[], ResponseFormat> convertStatus = getComponentsUtils().convertJsonToObjectUsingObjectMapper(dataList, new User(), ComponentInstance[].class, null, ComponentTypeEnum.RESOURCE_INSTANCE); + if (convertStatus.isRight()) { + return Either.right(convertStatus.right().value()); + } + + return Either.left(Arrays.asList(convertStatus.left().value())); + } + + private Either<RequirementCapabilityRelDef, ResponseFormat> convertToRequirementCapabilityRelDef(String data) { + + Either<RequirementCapabilityRelDef, ActionStatus> convertStatus = convertJsonToObject(data, RequirementCapabilityRelDef.class); + if (convertStatus.isRight()) { + return Either.right(getComponentsUtils().getResponseFormat(convertStatus.right().value())); + } + RequirementCapabilityRelDef requirementCapabilityRelDef = convertStatus.left().value(); + return Either.left(requirementCapabilityRelDef); + } + + private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) { + try { + log.trace("convert json to object. json=\n{}", data); + T t = null; + t = gson.fromJson(data, clazz); + if (t == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("object is null after converting from json"); + return Either.right(ActionStatus.INVALID_CONTENT); + } + return Either.left(t); + } catch (Exception e) { + // INVALID JSON + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("failed to convert from json", e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java new file mode 100644 index 0000000000..c5bebb41bf --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java @@ -0,0 +1,270 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.List; +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Component Servlet", description = "Component Servlet") +@Singleton +public class ComponentServlet extends BeGenericServlet { + private static Logger log = LoggerFactory.getLogger(ComponentServlet.class.getName()); + + @GET + @Path("/{componentType}/{componentId}/requirmentsCapabilities") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Component Requirments And Capabilities", httpMethod = "GET", notes = "Returns Requirments And Capabilities according to componentId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getRequirementAndCapabilities(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + Response response; + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + if (componentTypeEnum != null) { + ComponentBusinessLogic compBL = getComponentBL(componentTypeEnum, context); + Either<CapReqDef, ResponseFormat> eitherRequirementsAndCapabilities = compBL.getRequirementsAndCapabilities(componentId, componentTypeEnum, userId); + if (eitherRequirementsAndCapabilities.isRight()) { + response = buildErrorResponse(eitherRequirementsAndCapabilities.right().value()); + } else { + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), gson.toJson(eitherRequirementsAndCapabilities.left().value())); + } + } else { + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + return response; + } + + @GET + @Path("/{componentType}/latestversion/notabstract") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Component Requirments And Capabilities", httpMethod = "GET", notes = "Returns Requirments And Capabilities according to componentId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getLatestVersionNotAbstractCheckoutComponents(@PathParam("componentType") final String componentType, @Context final HttpServletRequest request, @QueryParam("internalComponentType") String internalComponentType, + @QueryParam("componentUids") List<String> componentUids, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + ComponentBusinessLogic businessLogic = getComponentBL(componentTypeEnum, context); + + log.debug("Received componentUids size is {}", (componentUids == null ? 0 : componentUids.size())); + + Either<List<Component>, ResponseFormat> actionResponse = businessLogic.getLatestVersionNotAbstractComponents(false, HighestFilterEnum.HIGHEST_ONLY, componentTypeEnum, internalComponentType, componentUids, userId); + + if (actionResponse.isRight()) { + log.debug("failed to get all non abstract {}", componentType); + return buildErrorResponse(actionResponse.right().value()); + } + Object components = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), components); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Certified Non Abstract" + componentType); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Non Abstract" + componentType); + log.debug("getCertifiedNotAbstractComponents failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + + } + + @POST + @Path("/{componentType}/latestversion/notabstract") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Component Requirments And Capabilities", httpMethod = "GET", notes = "Returns Requirments And Capabilities according to componentId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getLatestVersionNotAbstractCheckoutComponentsByBody(@PathParam("componentType") final String componentType, @Context final HttpServletRequest request, @QueryParam("internalComponentType") String internalComponentType, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "Consumer Object to be created", required = true) List<String> data) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + if (log.isDebugEnabled()) + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + ComponentBusinessLogic businessLogic = getComponentBL(componentTypeEnum, context); + List<String> componentUids = data; + if (log.isDebugEnabled()) + log.debug("Received componentUids size is {}", (componentUids == null ? 0 : componentUids.size())); + + // long start = System.currentTimeMillis(); + + Either<List<Component>, ResponseFormat> actionResponse = businessLogic.getLatestVersionNotAbstractComponents(false, HighestFilterEnum.HIGHEST_ONLY, componentTypeEnum, internalComponentType, componentUids, userId); + + // long endBl = System.currentTimeMillis(); + + if (actionResponse.isRight()) { + if (log.isDebugEnabled()) + log.debug("failed to get all non abstract {}", componentType); + return buildErrorResponse(actionResponse.right().value()); + + } + Object components = RepresentationUtils.toRepresentation(actionResponse.left().value()); + Response responseToReturn = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), components); + + long endResp = System.currentTimeMillis(); + + // log.info("********** Time calculation in ms: BL {} , Response {}, + // Total {}", (endBl - start ), (endResp - endBl), (endResp - + // start)); + return responseToReturn; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Certified Non Abstract" + componentType); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Non Abstract" + componentType); + log.debug("getCertifiedNotAbstractComponents failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + + } + + @GET + @Path("/{componentType}/latestversion/notabstract/uidonly") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Component uid only", httpMethod = "GET", notes = "Returns componentId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getLatestVersionNotAbstractCheckoutComponentsIdesOnly(@PathParam("componentType") final String componentType, @Context final HttpServletRequest request, @QueryParam("internalComponentType") String internalComponentType, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "uid list", required = true) String data) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + try { + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + ComponentBusinessLogic businessLogic = getComponentBL(componentTypeEnum, context); + + Either<List<Map<String, String>>, ResponseFormat> actionResponse = businessLogic.getLatestVersionNotAbstractComponentsUidOnly(false, HighestFilterEnum.HIGHEST_ONLY, componentTypeEnum, internalComponentType, userId); + if (actionResponse.isRight()) { + log.debug("failed to get all non abstract {}", componentType); + return buildErrorResponse(actionResponse.right().value()); + } + Object components = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), components); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Certified Non Abstract" + componentType); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Non Abstract" + componentType); + log.debug("getCertifiedNotAbstractComponents failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + + } + + @GET + @Path("/{componentType}/{componentId}/componentInstances") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Component instances", httpMethod = "GET", notes = "Returns component instances", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getComponentInstancesFilteredByPropertiesAndInputs(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + @QueryParam("searchText") String searchText, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "uid" + "" + "list", required = true) String data) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + try { + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + ComponentBusinessLogic businessLogic = getComponentBL(componentTypeEnum, context); + + Either<List<ComponentInstance>, ResponseFormat> actionResponse = businessLogic.getComponentInstancesFilteredByPropertiesAndInputs(componentId, componentTypeEnum, userId, searchText); + if (actionResponse.isRight()) { + log.debug("failed to get all component instances filtered by properties and inputs {}", componentType); + return buildErrorResponse(actionResponse.right().value()); + } + Object components = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), components); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Component Instances filtered by properties & inputs" + componentType); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Component Instances filtered by properties & inputs" + componentType); + log.debug("getComponentInstancesFilteredByPropertiesAndInputs failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConfigMgrServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConfigMgrServlet.java new file mode 100644 index 0000000000..164b1d7665 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConfigMgrServlet.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +import org.openecomp.sdc.be.config.Configuration; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.servlets.BasicServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/configmgr") +public class ConfigMgrServlet extends BasicServlet { + + private static Logger log = LoggerFactory.getLogger(ConfigMgrServlet.class.getName()); + + @GET + @Path("/get") + @Produces(MediaType.APPLICATION_JSON) + public String getConfig(@Context final HttpServletRequest request, @QueryParam("type") String type) { + + String result = null; + + ServletContext context = request.getSession().getServletContext(); + + ConfigurationManager configurationManager = (ConfigurationManager) context.getAttribute(Constants.CONFIGURATION_MANAGER_ATTR); + + if (type == null || type.equals("configuration")) { + + Configuration configuration = configurationManager.getConfiguration(); + if (configuration == null) { + log.warn("Configuration of type {} was not found", Configuration.class); + } else { + log.info("The value returned from getConfig is {}", configuration); + + result = gson.toJson(configuration); + + } + } + + return result; + + } + + @POST + @Path("/set1") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_JSON) + public String setConfig1(@Context final HttpServletRequest request, Configuration configuration) { + + log.debug("{}", configuration); + + return "ok"; + + } + + @POST + @Path("/set2") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_JSON) + public void setConfig2(@Context final HttpServletRequest request, Configuration configuration) { + + log.debug("{}", configuration); + + } + + @PUT + @Path("/setput1") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_JSON) + public String setConfig3(@Context final HttpServletRequest request, Configuration configuration) { + + log.debug("{}", configuration); + + return "ok"; + + } + + @PUT + @Path("/setput2") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_JSON) + public void setConfig4(@Context final HttpServletRequest request, Configuration configuration) { + + log.debug("{}", configuration); + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConfigServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConfigServlet.java new file mode 100644 index 0000000000..2a3a87d942 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConfigServlet.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +import org.openecomp.sdc.be.config.Configuration; +import org.openecomp.sdc.common.api.ConfigurationSource; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.servlets.BasicServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/config") +public class ConfigServlet extends BasicServlet { + + private static Logger log = LoggerFactory.getLogger(ConfigServlet.class.getName()); + + @GET + @Path("/get") + @Produces(MediaType.APPLICATION_JSON) + public String getConfig(@Context final HttpServletRequest request) { + + String result = null; + + ServletContext context = request.getSession().getServletContext(); + + ConfigurationSource configurationSource = (ConfigurationSource) context.getAttribute(Constants.CONFIGURATION_SOURCE_ATTR); + if (configurationSource != null) { + Configuration configuration = configurationSource.getAndWatchConfiguration(Configuration.class, null); + + if (configuration == null) { + log.warn("Configuration of type {} was not found", Configuration.class); + } + log.debug("{}", configuration); + if (log.isInfoEnabled()) { + log.debug("Info level ENABLED..."); + } + log.info("The value returned from getConfig is {}", configuration); + + result = gson.toJson(configuration); + + } else { + log.warn("Source Configuration object was not initialized in the context."); + } + + return result; + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConsumerServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConsumerServlet.java new file mode 100644 index 0000000000..0603f267ab --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ConsumerServlet.java @@ -0,0 +1,227 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.ConsumerBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.ConsumerDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.Gson; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/consumers") +@Api(value = "Consumer Servlet", description = "Consumer Servlet") +@Singleton +public class ConsumerServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(ConsumerServlet.class.getName()); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Consumer credentials", httpMethod = "POST", notes = "Returns created ECOMP consumer credentials", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Consumer credentials created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response createConsumer(@ApiParam(value = "Consumer Object to be created", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + try { + ConsumerBusinessLogic businessLogic = getConsumerBL(context); + + Either<ConsumerDefinition, ResponseFormat> convertionResponse = convertJsonToObject(data, modifier, AuditingActionEnum.ADD_ECOMP_USER_CREDENTIALS); + + if (convertionResponse.isRight()) { + log.debug("failed to create Consumer"); + return buildErrorResponse(convertionResponse.right().value()); + } + + ConsumerDefinition consumer = convertionResponse.left().value(); + + Either<ConsumerDefinition, ResponseFormat> actionResult = businessLogic.createConsumer(modifier, consumer); + + if (actionResult.isRight()) { + log.debug("failed to create Consumer"); + return buildErrorResponse(actionResult.right().value()); + } + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResult.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create consumer"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create consumer"); + log.debug("create consumer failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + @GET + @Path("/{consumerId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Consumer", httpMethod = "GET", notes = "Returns consumer according to ConsumerID", response = ConsumerDefinition.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Consumer found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Consumer not found") }) + public Response getConsumer(@PathParam("consumerId") final String consumerId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ConsumerBusinessLogic businessLogic = getConsumerBL(context); + + Either<ConsumerDefinition, ResponseFormat> actionResponse = businessLogic.getConsumer(consumerId, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to get consumer"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Consumer"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Consumer"); + log.debug("get consumer failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @DELETE + @Path("/{consumerId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Deletes Consumer", httpMethod = "DELETE", notes = "Returns deleted consumer according to ConsumerID", response = ConsumerDefinition.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "Consumer deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Consumer not found") }) + public Response deleteConsumer(@PathParam("consumerId") final String consumerId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ConsumerBusinessLogic businessLogic = getConsumerBL(context); + + Either<ConsumerDefinition, ResponseFormat> actionResponse = businessLogic.deleteConsumer(consumerId, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to delete consumer"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Consumer"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Consumer"); + log.debug("delete consumer failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + private ConsumerBusinessLogic getConsumerBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + ConsumerBusinessLogic consumerBL = webApplicationContext.getBean(ConsumerBusinessLogic.class); + + return consumerBL; + } + + public Either<ConsumerDefinition, ResponseFormat> convertJsonToObject(String data, User user, AuditingActionEnum actionEnum) { + ConsumerDefinition consumer = null; + Gson gson = new Gson(); + try { + log.trace("convert json to object. json=\n{}", data); + consumer = gson.fromJson(data, ConsumerDefinition.class); + if (consumer == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("object is null after converting from json"); + ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(user, actionEnum); + return Either.right(responseFormat); + } + } catch (Exception e) { + // INVALID JSON + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("failed to convert from json {}", data, e); + ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(user, actionEnum); + return Either.right(responseFormat); + } + return Either.left(consumer); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CsarBuildServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CsarBuildServlet.java new file mode 100644 index 0000000000..4ba6b7516d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CsarBuildServlet.java @@ -0,0 +1,296 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +//import org.openecomp.sdc.be.builders.tosca.api.TopologyService; +//import org.openecomp.sdc.be.tosca.parsers.ParserMode; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/services") +public class CsarBuildServlet extends ToscaDaoServlet { + + private static Logger log = LoggerFactory.getLogger(CsarBuildServlet.class.getName()); + + @GET + @Path("/{serviceName}/{serviceVersion}") + public Response getDefaultTemplate(@Context final HttpServletRequest request, @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion) { + + return null;// buildToscaCsar(request, serviceName, serviceVersion); + + } + + @GET + @Path("/{serviceName}/{serviceVersion}/csar") + public Response getToscaCsarTemplate(@Context final HttpServletRequest request, @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion) { + + return null; // buildToscaCsar(request, serviceName, serviceVersion); + + } + + /* + * private Response buildToscaCsar(final HttpServletRequest request, String serviceName, String serviceVersion) { log.debug("Building CSAR for service:{} , version:{}", serviceName, serviceVersion); ServletContext context = + * request.getSession().getServletContext(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream); String fileName = + * serviceName+"_"+serviceVersion+".zip"; + * + * IResourceUploader resourceUploader = getResourceUploader(context); TopologyService topologyService = getToscaYamlBuilder(context).getServiceYaml(serviceName, serviceVersion, ParserMode.CSAR, "Scripts"); try { + * + * + * //Add Service yml to Zip addZipEntry(zipOutputStream, "Definitions/"+serviceName+".yaml", topologyService.getTopologyServiceYaml()); + * + * //Add Resources to Zip addResourcesToZip(zipOutputStream, topologyService); + * + * //Add Artifacts to Zip addArtifactsToZip(serviceName, serviceVersion, zipOutputStream, resourceUploader); + * + * //Prepare Tosca metadata addToscaMetaToZip(zipOutputStream, topologyService, resourceUploader); + * + * } + * + * catch (IOException e) { log.error("Failed to create CSAR file", e); return null; } finally{ try { byteArrayOutputStream.close(); zipOutputStream.close(); } catch (IOException e) { log.error("Failed to close output srream", e); } + * + * } return buildResponse(fileName, byteArrayOutputStream); + * + * + * } + */ + + public static final String TOSCA_META_PATH = "TOSCA-Metadata/TOSCA.meta"; + // protected void addToscaMetaToZip(ZipOutputStream zipOutputStream, + // TopologyService topService, IResourceUploader resUploader) throws + // IOException { + // String serviceVersion = topService.getTopologyVersion(); + // String serviceName = topService.getTopologyName(); + // StringBuffer buff = new StringBuffer(); + // + // String[] serviceToscaMeta = prepareToscaMetaHeader(serviceName); + // + // for( String toAppend : serviceToscaMeta){ + // buff.append(toAppend); + // } + // + // List<String> toscaMetaComponents = + // prepareToscaMetaComponents(topService.getDependenciesYamls().keySet()); + // for( String toAppend : toscaMetaComponents ){ + // buff.append(toAppend); + // } + // + // Either<ServiceArtifactsDataCollection, ResourceUploadStatus> + // getServiceArtifactsCollectionStatus = + // Either.right(ResourceUploadStatus.ERROR);//resUploader.getServiceArtifactsCollection(serviceName, + // serviceVersion); + // if(getServiceArtifactsCollectionStatus.isLeft()){ + // List<String> toscaMetaArtifacts = + // prepareToscaMetaArtifacts(getServiceArtifactsCollectionStatus.left().value()); + // for( String toAppend : toscaMetaArtifacts ){ + // buff.append(toAppend); + // } + // } + // + // addZipEntry(zipOutputStream, TOSCA_META_PATH, buff.toString()); + // } + + // protected List<String> prepareToscaMetaArtifacts( + // ServiceArtifactsDataCollection serviceArtifactsDataCollection) { + // List<String> artifactsForToscaMeta = new ArrayList<String>(); + // Iterator<Entry<String, List<ArtifactData>>> nodeTemplateArtifactsItr = + // serviceArtifactsDataCollection.getServiceArtifactDataMap().entrySet().iterator(); + // while( nodeTemplateArtifactsItr.hasNext() ){ + // Entry<String, List<ArtifactData>> nodeNameArtifacts = + // nodeTemplateArtifactsItr.next(); + // String nodeName = nodeNameArtifacts.getKey(); + // Iterator<ArtifactData> artifactDataItr = + // nodeNameArtifacts.getValue().iterator(); + // while( artifactDataItr.hasNext() ){ + // ArtifactData artifactData = artifactDataItr.next(); + // artifactsForToscaMeta.add("\n"); + // artifactsForToscaMeta.add("Name: "+getArtifactPath(nodeName, + // artifactData)+"\n"); + // artifactsForToscaMeta.add("Content-Type: + // application/"+getAppliactionMime(artifactData.getArtifactName())+"\n"); + // } + // } + // return artifactsForToscaMeta; + // } + + // protected List<String> prepareToscaMetaComponents(Set<String> components) + // { + // Iterator<String> resourceNameItr = components.iterator(); + // List<String> componentsForToscaMeta = new ArrayList<String>(); + // while( resourceNameItr.hasNext() ){ + // String resourceName = resourceNameItr.next(); + // componentsForToscaMeta.add("\n"); + // componentsForToscaMeta.add("Name: "+getResourcePath(resourceName)+"\n"); + // componentsForToscaMeta.add("Content-Type: + // application/vnd.oasis.tosca.definitions.yaml\n"); + // + // } + // return componentsForToscaMeta; + // } + + protected String[] prepareToscaMetaHeader(String serviceName) { + return new String[] { "TOSCA-Meta-File-Version: 1.0\n", "CSAR-Version: 1.1\n", "Created-By: INTERWISE\n", "\n", "Entry-Definitions: Definitions/" + serviceName + ".yaml\n", "\n", "Name: Definitions/" + serviceName + ".yaml\n", + "Content-Type: application/vnd.oasis.tosca.definitions.yaml\n" }; + } + + protected String getAppliactionMime(String fileName) { + String mimeType; + if (fileName.contains(".sh")) { + mimeType = "x-sh"; + } else if (fileName.contains(".yang")) { + mimeType = "yang"; + } + + else if (fileName.contains(".rar")) { + mimeType = "x-rar-compressed"; + } + + else if (fileName.contains(".zip")) { + mimeType = "zip"; + } + + else if (fileName.contains(".tar")) { + mimeType = "x-tar"; + } + + else if (fileName.contains(".7z")) { + mimeType = "x-7z-compressed"; + } + + else { + // Undefined + mimeType = "undefined"; + } + return mimeType; + } + + // protected void addResourcesToZip(ZipOutputStream zipOutputStream, + // TopologyService topService) throws IOException { + // Iterator<Entry<String, String>> resourceNameDataItr = + // topService.getDependenciesYamls().entrySet().iterator(); + // while( resourceNameDataItr.hasNext() ){ + // Entry<String, String> resourceNameData = resourceNameDataItr.next(); + // addZipEntry(zipOutputStream, getResourcePath(resourceNameData.getKey()), + // resourceNameData.getValue()); + // } + // } + + protected String getArtifactPath(String nodeTamplateName, ESArtifactData artifactData) { + // return "Scripts/"+nodeTamplateName+"/"+ + // artifactData.getArtifactName(); + return "Scripts/" + nodeTamplateName + "/" + artifactData.getId(); + } + + protected String getResourcePath(String resourceName) { + return "Definitions/" + resourceName + ".yaml"; + } + + // protected void addArtifactsToZip(String serviceName, String + // serviceVersion, ZipOutputStream zipOutputStream, IResourceUploader + // resourceUploader) + // throws IOException { + // //Add Artifacts to Zip + // Either<ServiceArtifactsDataCollection, ResourceUploadStatus> + // getServiceArtifactsCollectionStatus = + // Either.right(ResourceUploadStatus.ERROR);//resourceUploader.getServiceArtifactsCollection(serviceName, + // serviceVersion); + // if(getServiceArtifactsCollectionStatus.isLeft()){ + // Iterator<Entry<String, List<ArtifactData>>> nodeTemplateArtifactsItr + // =getServiceArtifactsCollectionStatus.left().value().getServiceArtifactDataMap().entrySet().iterator(); + // while( nodeTemplateArtifactsItr.hasNext() ){ + // Entry<String, List<ArtifactData>> nodeTemplateArtifacts = + // nodeTemplateArtifactsItr.next(); + // String nodeTamplateName = nodeTemplateArtifacts.getKey(); + // List<ArtifactData> artifacts = nodeTemplateArtifacts.getValue(); + // for(ArtifactData artifactData : artifacts ){ + // addZipEntry(zipOutputStream, + // getArtifactPath(nodeTamplateName,artifactData), artifactData.getData()); + // } + // + // } + // } + // } + + // private Response buildResponse(String fileName, ByteArrayOutputStream + // fileOutputStream) { + // final InputStream inputStream = new + // ByteArrayInputStream(fileOutputStream.toByteArray()); + // + // StreamingOutput stream = new StreamingOutput() { + // public void write(OutputStream output) throws WebApplicationException { + // try { + // IOUtils.copy(inputStream, output); + // } catch (Exception e) { + // throw new WebApplicationException(e); + // } + // } + // }; + // + // return + // Response.ok(stream).type(MediaType.APPLICATION_OCTET_STREAM_TYPE).header("content-disposition","attachment; + // filename = "+fileName).build(); + // } + + // protected void addZipEntry(ZipOutputStream zipOutputStream, String + // filePath, String data) throws IOException { + // addZipEntry(zipOutputStream, filePath, encodeString(data)); + // } + + private byte[] encodeString(String data) throws CharacterCodingException { + Charset charset = Charset.forName("UTF-8"); + CharsetEncoder encoder = charset.newEncoder(); + ByteBuffer bb = encoder.encode(CharBuffer.wrap(data.toCharArray())); + byte[] ba = new byte[bb.limit()]; + bb.get(ba); + return ba; + } + + // private void addZipEntry(ZipOutputStream zipOutputStream, String + // filePath, byte[] data) throws IOException { + // log.debug("Adding to CSAR zip :{}", filePath); + // ZipEntry entry = new ZipEntry(filePath); + // zipOutputStream.putNextEntry(entry); + // zipOutputStream.write(data); + // zipOutputStream.closeEntry(); + // } + + @Override + public Logger getLogger() { + return log; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DistributionServiceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DistributionServiceServlet.java new file mode 100644 index 0000000000..62a321fa5b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DistributionServiceServlet.java @@ -0,0 +1,169 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.annotation.Resource; +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.DistributionMonitoringBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.info.DistributionStatusListResponse; +import org.openecomp.sdc.be.info.DistributionStatusOfServiceListResponce; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Distribution Service Servlet", description = "Distribution Service Servlet") +@Singleton +public class DistributionServiceServlet extends BeGenericServlet { + private static Logger log = LoggerFactory.getLogger(DistributionServiceServlet.class.getName()); + + @Resource + private DistributionMonitoringBusinessLogic distributionMonitoringLogic; + + @GET + @Path("/services/{serviceUUID}/distribution") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Distributions", httpMethod = "GET", notes = "Returns list bases on the information extracted from Auditing Records according to service uuid", response = DistributionStatusListResponse.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Service not found") }) + public Response getServiceById(@PathParam("serviceUUID") final String serviceUUID, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + init(request); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + Response response = null; + ResponseFormat responseFormat = null; + + try { + Either<DistributionStatusOfServiceListResponce, ResponseFormat> actionResponse = distributionMonitoringLogic.getListOfDistributionServiceStatus(serviceUUID, userId); + + if (actionResponse.isRight()) { + + responseFormat = actionResponse.right().value(); + response = buildErrorResponse(responseFormat); + } else { + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + response = buildOkResponse(responseFormat, actionResponse.left().value()); + + } + + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Distribution list for Service"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Distribution list for Service"); + log.debug("failed to get service distribution statuses", e); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + + response = buildErrorResponse(responseFormat); + return response; + } + + } + + @GET + @Path("/services/distribution/{did}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Distributions", httpMethod = "GET", notes = "Return the list of distribution status objects", response = DistributionStatusListResponse.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Status not found") }) + public Response getListOfDistributionStatuses(@PathParam("did") final String did, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + init(request); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + Response response = null; + ResponseFormat responseFormat = null; + + try { + Either<DistributionStatusListResponse, ResponseFormat> actionResponse = distributionMonitoringLogic.getListOfDistributionStatus(did, userId); + + if (actionResponse.isRight()) { + + responseFormat = actionResponse.right().value(); + log.debug("failed to fount statuses for did {} {}", did, responseFormat); + response = buildErrorResponse(responseFormat); + } else { + + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + log.debug("success to fount statuses for did {} {}", did, actionResponse.left().value()); + response = buildOkResponse(responseFormat, actionResponse.left().value()); + + } + + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Distribution Status"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Distribution Status"); + log.debug("failed to get distribution status ", e); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + + response = buildErrorResponse(responseFormat); + return response; + } + + } + + private void init(HttpServletRequest request) { + if (distributionMonitoringLogic == null) { + distributionMonitoringLogic = getDistributionBL(request.getSession().getServletContext()); + } + } + + private DistributionMonitoringBusinessLogic getDistributionBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + DistributionMonitoringBusinessLogic distributionBl = webApplicationContext.getBean(DistributionMonitoringBusinessLogic.class); + return distributionBl; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java new file mode 100644 index 0000000000..433a1bfc58 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java @@ -0,0 +1,611 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.clean.ComponentsCleanBusinessLogic; +import org.openecomp.sdc.be.components.impl.ElementBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.info.ArtifactTypesInfo; +import org.openecomp.sdc.be.model.ArtifactType; +import org.openecomp.sdc.be.model.Category; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.PropertyScope; +import org.openecomp.sdc.be.model.Tag; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Path("/v1/") + +/**** + * + * UI oriented servlet - to return elements in specific format UI needs + * + * + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Api(value = "Element Servlet", description = "Element Servlet") +@Singleton +public class ElementServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(ElementServlet.class.getName()); + + /* + ****************************************************************************** + * NEW CATEGORIES category / \ subcategory subcategory / grouping + ******************************************************************************/ + + /* + * + * + * CATEGORIES + */ + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all component categories + @GET + @Path("/categories/{componentType}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve the list of all resource/service/product categories/sub-categories/groupings", httpMethod = "GET", notes = "Retrieve the list of all resource/service/product categories/sub-categories/groupings.", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns categories Ok"), @ApiResponse(code = 403, message = "Missing information"), @ApiResponse(code = 400, message = "Invalid component type"), + @ApiResponse(code = 409, message = "Restricted operation"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getComponentCategories(@ApiParam(value = "allowed values are resources / services/ products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) @PathParam(value = "componentType") final String componentType, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @Context final HttpServletRequest request) { + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<List<CategoryDefinition>, ResponseFormat> either = elementBL.getAllCategories(componentType, userId); + if (either.isRight()) { + log.debug("No categories were found for type {}", componentType); + return buildErrorResponse(either.right().value()); + } else { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), either.left().value()); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Component Categories"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Component Categories"); + log.debug("getComponentCategories failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @POST + @Path("/category/{componentType}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create new component category", httpMethod = "POST", notes = "Create new component category") + @ApiResponses(value = { @ApiResponse(code = 201, message = "Category created"), @ApiResponse(code = 400, message = "Invalid category data"), @ApiResponse(code = 403, message = "USER_ID header is missing"), + @ApiResponse(code = 409, message = "Category already exists / User not permitted to perform the action"), @ApiResponse(code = 500, message = "General Error") }) + public Response createComponentCategory( + @ApiParam(value = "allowed values are resources /services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) @PathParam(value = "componentType") final String componentType, + @ApiParam(value = "Category to be created", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + CategoryDefinition category = RepresentationUtils.fromRepresentation(data, CategoryDefinition.class); + + Either<CategoryDefinition, ResponseFormat> createResourceCategory = elementBL.createCategory(category, componentType, userId); + if (createResourceCategory.isRight()) { + return buildErrorResponse(createResourceCategory.right().value()); + } + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); + return buildOkResponse(responseFormat, createResourceCategory.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create resource category"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create resource category"); + log.debug("createResourceCategory failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @DELETE + @Path("/category/{componentType}/{categoryUniqueId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete component category", httpMethod = "DELETE", notes = "Delete component category", response = Category.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "Category deleted"), @ApiResponse(code = 403, message = "USER_ID header is missing"), @ApiResponse(code = 409, message = "User not permitted to perform the action"), + @ApiResponse(code = 404, message = "Category not found"), @ApiResponse(code = 500, message = "General Error") }) + public Response deleteComponentCategory(@PathParam(value = "categoryUniqueId") final String categoryUniqueId, @PathParam(value = "componentType") final String componentType, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<CategoryDefinition, ResponseFormat> createResourceCategory = elementBL.deleteCategory(categoryUniqueId, componentType, userId); + + if (createResourceCategory.isRight()) { + return buildErrorResponse(createResourceCategory.right().value()); + } + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); + return buildOkResponse(responseFormat, null); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create resource category"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create resource category"); + log.debug("createResourceCategory failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + /* + * + * + * SUBCATEGORIES + * + */ + + @POST + @Path("/category/{componentType}/{categoryId}/subCategory") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create new component sub-category", httpMethod = "POST", notes = "Create new component sub-category for existing category") + @ApiResponses(value = { @ApiResponse(code = 201, message = "Subcategory created"), @ApiResponse(code = 400, message = "Invalid subcategory data"), @ApiResponse(code = 403, message = "USER_ID header is missing"), + @ApiResponse(code = 404, message = "Parent category wasn't found"), @ApiResponse(code = 409, message = "Subcategory already exists / User not permitted to perform the action"), @ApiResponse(code = 500, message = "General Error") }) + public Response createComponentSubCategory( + @ApiParam(value = "allowed values are resources / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) @PathParam(value = "componentType") final String componentType, + @ApiParam(value = "Parent category unique ID", required = true) @PathParam(value = "categoryId") final String categoryId, @ApiParam(value = "Subcategory to be created. \ne.g. {\"name\":\"Resource-subcat\"}", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + SubCategoryDefinition subCategory = RepresentationUtils.fromRepresentation(data, SubCategoryDefinition.class); + + Either<SubCategoryDefinition, ResponseFormat> createSubcategory = elementBL.createSubCategory(subCategory, componentType, categoryId, userId); + if (createSubcategory.isRight()) { + return buildErrorResponse(createSubcategory.right().value()); + } + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); + return buildOkResponse(responseFormat, createSubcategory.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create sub-category"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create sub-category"); + log.debug("createComponentSubCategory failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @DELETE + @Path("/category/{componentType}/{categoryUniqueId}/subCategory/{subCategoryUniqueId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete component category", httpMethod = "DELETE", notes = "Delete component category", response = Category.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "Category deleted"), @ApiResponse(code = 403, message = "USER_ID header is missing"), @ApiResponse(code = 409, message = "User not permitted to perform the action"), + @ApiResponse(code = 404, message = "Category not found"), @ApiResponse(code = 500, message = "General Error") }) + public Response deleteComponentSubCategory(@PathParam(value = "categoryUniqueId") final String categoryUniqueId, @PathParam(value = "subCategoryUniqueId") final String subCategoryUniqueId, + @PathParam(value = "componentType") final String componentType, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<SubCategoryDefinition, ResponseFormat> deleteSubResourceCategory = elementBL.deleteSubCategory(categoryUniqueId, subCategoryUniqueId, componentType, userId); + if (deleteSubResourceCategory.isRight()) { + return buildErrorResponse(deleteSubResourceCategory.right().value()); + } + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); + return buildOkResponse(responseFormat, null); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete component category"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete component category"); + log.debug("deleteComponentSubCategory failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + /* + * GROUPINGS + */ + @POST + @Path("/category/{componentType}/{categoryId}/subCategory/{subCategoryId}/grouping") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create new component grouping", httpMethod = "POST", notes = "Create new component grouping for existing sub-category") + @ApiResponses(value = { @ApiResponse(code = 201, message = "Grouping created"), @ApiResponse(code = 400, message = "Invalid grouping data"), @ApiResponse(code = 403, message = "USER_ID header is missing"), + @ApiResponse(code = 404, message = "Parent category or subcategory were not found"), @ApiResponse(code = 409, message = "Grouping already exists / User not permitted to perform the action"), + @ApiResponse(code = 500, message = "General Error") }) + public Response createComponentGrouping(@ApiParam(value = "allowed values are products", allowableValues = ComponentTypeEnum.PRODUCT_PARAM_NAME, required = true) @PathParam(value = "componentType") final String componentType, + @ApiParam(value = "Parent category unique ID", required = true) @PathParam(value = "categoryId") final String grandParentCategoryId, + @ApiParam(value = "Parent sub-category unique ID", required = true) @PathParam(value = "subCategoryId") final String parentSubCategoryId, @ApiParam(value = "Subcategory to be created", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + GroupingDefinition grouping = RepresentationUtils.fromRepresentation(data, GroupingDefinition.class); + + Either<GroupingDefinition, ResponseFormat> createGrouping = elementBL.createGrouping(grouping, componentType, grandParentCategoryId, parentSubCategoryId, userId); + if (createGrouping.isRight()) { + return buildErrorResponse(createGrouping.right().value()); + } + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); + return buildOkResponse(responseFormat, createGrouping.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create grouping"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create grouping"); + log.debug("createComponentGrouping failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @DELETE + @Path("/category/{componentType}/{categoryUniqueId}/subCategory/{subCategoryUniqueId}/grouping/{groupingUniqueId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete component category", httpMethod = "DELETE", notes = "Delete component category", response = Category.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "Category deleted"), @ApiResponse(code = 403, message = "USER_ID header is missing"), @ApiResponse(code = 409, message = "User not permitted to perform the action"), + @ApiResponse(code = 404, message = "Category not found"), @ApiResponse(code = 500, message = "General Error") }) + public Response deleteComponentGrouping(@PathParam(value = "categoryUniqueId") final String grandParentCategoryUniqueId, @PathParam(value = "subCategoryUniqueId") final String parentSubCategoryUniqueId, + @PathParam(value = "groupingUniqueId") final String groupingUniqueId, @PathParam(value = "componentType") final String componentType, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<GroupingDefinition, ResponseFormat> deleteGrouping = elementBL.deleteGrouping(grandParentCategoryUniqueId, parentSubCategoryUniqueId, groupingUniqueId, componentType, userId); + if (deleteGrouping.isRight()) { + return buildErrorResponse(deleteGrouping.right().value()); + } + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); + return buildOkResponse(responseFormat, null); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete component grouping"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete component grouping"); + log.debug("deleteGrouping failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all tags + @GET + @Path("/tags") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve all tags", httpMethod = "GET", notes = "Retrieve all tags", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns tags Ok"), @ApiResponse(code = 404, message = "No tags were found"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getTags(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getTags) Start handle request of {}", url); + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<List<Tag>, ActionStatus> either = elementBL.getAllTags(userId); + if (either.isRight() || either.left().value() == null) { + log.debug("No tags were found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), either.left().value()); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get All Tags"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get All Tags"); + log.debug("getAllTags failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all property scopes + @GET + @Path("/propertyScopes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve all propertyScopes", httpMethod = "GET", notes = "Retrieve all propertyScopes", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns propertyScopes Ok"), @ApiResponse(code = 404, message = "No propertyScopes were found"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getPropertyScopes(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getPropertyScopes) Start handle request of {}", url); + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<List<PropertyScope>, ActionStatus> either = elementBL.getAllPropertyScopes(userId); + if (either.isRight() || either.left().value() == null) { + log.debug("No property scopes were found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), either.left().value()); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Property Scopes Categories"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property Scopes Categories"); + log.debug("getPropertyScopes failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all artifact types + @GET + @Path("/artifactTypes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve all artifactTypes", httpMethod = "GET", notes = "Retrieve all artifactTypes", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns artifactTypes Ok"), @ApiResponse(code = 404, message = "No artifactTypes were found"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getArtifactTypes(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getArtifactTypes) Start handle request of {}", url); + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<List<ArtifactType>, ActionStatus> either = elementBL.getAllArtifactTypes(userId); + if (either.isRight() || either.left().value() == null) { + log.debug("No artifact types were found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else { + + Integer defaultHeatTimeout = ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultHeatArtifactTimeoutMinutes(); + ArtifactTypesInfo typesResponse = new ArtifactTypesInfo(); + typesResponse.setArtifactTypes(either.left().value()); + typesResponse.setHeatDefaultTimeout(defaultHeatTimeout); + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), typesResponse); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Artifact Types"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Artifact Types"); + log.debug("getArtifactTypes failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all artifact types + @GET + @Path("/configuration/ui") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve all artifactTypes", httpMethod = "GET", notes = "Retrieve all artifactTypes", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns artifactTypes Ok"), @ApiResponse(code = 404, message = "No artifactTypes were found"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getConfiguration(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getConfiguration) Start handle request of {}", url); + + try { + ElementBusinessLogic elementBL = getElementBL(request.getSession().getServletContext()); + Either<List<ArtifactType>, ActionStatus> otherEither = elementBL.getAllArtifactTypes(userId); + Either<Integer, ActionStatus> defaultHeatTimeout = elementBL.getDefaultHeatTimeout(); + Either<Map<String, Object>, ActionStatus> deploymentEither = elementBL.getAllDeploymentArtifactTypes(); + Either<Map<String, String>, ActionStatus> resourceTypesMap = elementBL.getResourceTypesMap(); + + if (otherEither.isRight() || otherEither.left().value() == null) { + log.debug("No other artifact types were found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else if (deploymentEither.isRight() || deploymentEither.left().value() == null) { + log.debug("No deployment artifact types were found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else if (defaultHeatTimeout.isRight() || defaultHeatTimeout.left().value() == null) { + log.debug("heat default timeout was not found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else if (resourceTypesMap.isRight() || resourceTypesMap.left().value() == null) { + log.debug("No resource types were found"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT)); + } else { + Map<String, Object> artifacts = new HashMap<String, Object>(); + Map<String, Object> configuration = new HashMap<String, Object>(); + + artifacts.put("other", otherEither.left().value()); + artifacts.put("deployment", deploymentEither.left().value()); + configuration.put("artifacts", artifacts); + configuration.put("defaultHeatTimeout", defaultHeatTimeout.left().value()); + configuration.put("componentTypes", elementBL.getAllComponentTypesParamNames()); + configuration.put("roles", elementBL.getAllSupportedRoles()); + configuration.put("resourceTypes", resourceTypesMap.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), configuration); + } + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Artifact Types"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Artifact Types"); + log.debug("getArtifactTypes failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all followed resources and services + @GET + @Path("/followed") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve all followed", httpMethod = "GET", notes = "Retrieve all followed", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns followed Ok"), @ApiResponse(code = 404, message = "No followed were found"), @ApiResponse(code = 404, message = "User not found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getFollowedResourcesServices(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + Response res = null; + User userData = null; + try { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + UserBusinessLogic userAdminManager = getUserAdminManager(request.getSession().getServletContext()); + + // Getting the user + Either<User, ActionStatus> either = userAdminManager.getUser(userId, false); + if (either.isRight()) { + // Couldn't find or otherwise fetch the user + return buildErrorResponse(getComponentsUtils().getResponseFormatByUserId(either.right().value(), userId)); + } + + if (either.left().value() != null) { + userData = either.left().value(); + Either<Map<String, List<? extends Component>>, ResponseFormat> followedResourcesServices = getElementBL(request.getSession().getServletContext()).getFollowed(userData); + // res = + // buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), + // followedResourcesServices.left().value()); + if (followedResourcesServices.isRight()) { + log.debug("failed to get followed resources services "); + return buildErrorResponse(followedResourcesServices.right().value()); + } + Object data = RepresentationUtils.toRepresentation(followedResourcesServices.left().value()); + res = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), data); + } else { + res = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Followed Resources / Services Categories"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Followed Resources / Services Categories"); + log.debug("Getting followed resources/services failed with exception", e); + res = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + return res; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all certified resources and services and their last version + @GET + @Path("/screen") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve catalog resources and services", httpMethod = "GET", notes = "Retrieve catalog resources and services", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns resources and services Ok"), @ApiResponse(code = 404, message = "No resources and services were found"), @ApiResponse(code = 404, message = "User not found"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getCatalogComponents(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + Response res = null; + try { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + Either<Map<String, List<? extends Component>>, ResponseFormat> catalogData = getElementBL(request.getSession().getServletContext()).getCatalogComponents(userId); + + if (catalogData.isRight()) { + log.debug("failed to get catalog data"); + return buildErrorResponse(catalogData.right().value()); + } + Object data = RepresentationUtils.toRepresentation(catalogData.left().value()); + res = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), data); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Catalog Components"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Catalog Components"); + log.debug("Getting catalog components failed with exception", e); + res = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + return res; + } + + @DELETE + @Path("/inactiveComponents/{componentType}") + public Response deleteMarkedResources(@PathParam("componentType") final String componentType, @Context final HttpServletRequest request) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + String userId = request.getHeader(Constants.USER_ID_HEADER); + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + NodeTypeEnum nodeType = NodeTypeEnum.getByNameIgnoreCase(componentType); + if (nodeType == null) { + log.info("componentType is not valid: {}", componentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + + List<NodeTypeEnum> componentsList = new ArrayList<NodeTypeEnum>(); + componentsList.add(nodeType); + try { + ComponentsCleanBusinessLogic businessLogic = getComponentCleanerBL(context); + Map<NodeTypeEnum, Either<List<String>, ResponseFormat>> cleanComponentsResult = businessLogic.cleanComponents(componentsList); + Either<List<String>, ResponseFormat> cleanResult = cleanComponentsResult.get(nodeType); + + if (cleanResult.isRight()) { + log.debug("failed to delete marked components of type {}", nodeType); + response = buildErrorResponse(cleanResult.right().value()); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), cleanResult.left().value()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Marked Components"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Marked Components"); + log.debug("delete marked components failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/ecompPortalMenu") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve ecomp portal menu - MOC", httpMethod = "GET", notes = "Retrieve ecomp portal menu", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Retrieve ecomp portal menu") }) + public Response getListOfCsars(@Context final HttpServletRequest request) { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), + "[{\"menuId\":1,\"column\":2,\"text\":\"Design\",\"parentMenuId\":null,\"url\":\"\",\"appid\":null,\"roles\":null,\"children\":[{\"menuId\":11,\"column\":1,\"text\":\"ProductDesign\",\"parentMenuId\":1,\"url\":\"\",\"appid\":null,\"roles\":null},{\"menuId\":12,\"column\":2,\"text\":\"Service\",\"parentMenuId\":1,\"url\":\"\",\"appid\":null,\"roles\":null,\"children\":[{\"menuId\":21,\"column\":1,\"text\":\"ViewPolicies\",\"parentMenuId\":12,\"url\":\"\",\"appid\":null,\"roles\":null,\"children\":[{\"menuId\":90,\"column\":1,\"text\":\"4thLevelApp1aR16\",\"parentMenuId\":21,\"url\":\"http://google.com\",\"appid\":null,\"roles\":null}]},{\"menuId\":22,\"column\":2,\"text\":\"UpdatePolicies\",\"parentMenuId\":12,\"url\":\"\",\"appid\":null,\"roles\":null,\"children\":[{\"menuId\":91,\"column\":1,\"text\":\"4thLevelApp1bR16\",\"parentMenuId\":22,\"url\":\"http://jsonlint.com/\",\"appid\":null,\"roles\":null}]},{\"menuId\":23,\"column\":3,\"text\":\"UpdateRules\",\"parentMenuId\":12,\"url\":\"\",\"appid\":null,\"roles\":null},{\"menuId\":24,\"column\":4,\"text\":\"CreateSignatures?\",\"parentMenuId\":12,\"url\":\"\",\"appid\":null,\"roles\":null},{\"menuId\":25,\"column\":5,\"text\":\"Definedata\",\"parentMenuId\":12,\"url\":\"\",\"appid\":null,\"roles\":null}]}]}]"); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/GroupServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/GroupServlet.java new file mode 100644 index 0000000000..bde8f93929 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/GroupServlet.java @@ -0,0 +1,182 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.GroupBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.info.GroupDefinitionInfo; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Resource Group Servlet", description = "Resource Group Servlet") +@Singleton +public class GroupServlet extends AbstractValidationsServlet { + + private static Logger log = LoggerFactory.getLogger(GroupServlet.class.getName()); + + private Gson gson = new Gson(); + + @GET + @Path("/{containerComponentType}/{componentId}/groups/{groupId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get group artifacts ", httpMethod = "GET", notes = "Returns artifacts metadata according to groupId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "group found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Group not found") }) + public Response getGroupArtifactById(@PathParam("containerComponentType") final String containerComponentType, @PathParam("componentId") final String componentId, @PathParam("groupId") final String groupId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + + GroupBusinessLogic businessLogic = this.getGroupBL(context); + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + Either<GroupDefinitionInfo, ResponseFormat> actionResponse = businessLogic.getGroupWithArtifactsById(componentTypeEnum, componentId, groupId, userId, false); + + if (actionResponse.isRight()) { + log.debug("failed to get all non abstract {}", containerComponentType); + return buildErrorResponse(actionResponse.right().value()); + } + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "getGroupArtifactById"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("getGroupArtifactById"); + log.debug("getGroupArtifactById unexpected exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + @PUT + @Path("/{containerComponentType}/{componentId}/groups/{groupUniqueId}/metadata") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Group Metadata", httpMethod = "PUT", notes = "Returns updated group definition", response = GroupDefinition.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Group Updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateGroupMetadata(@PathParam("containerComponentType") final String containerComponentType, @PathParam("componentId") final String componentId, @PathParam("groupUniqueId") final String groupUniqueId, + @ApiParam(value = "Service object to be Updated", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User user = new User(); + user.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + GroupBusinessLogic businessLogic = getGroupBL(context); + + Either<GroupDefinition, ResponseFormat> convertResponse = parseToGroup(data); + if (convertResponse.isRight()) { + log.debug("failed to parse group"); + response = buildErrorResponse(convertResponse.right().value()); + return response; + } + GroupDefinition updatedGroup = convertResponse.left().value(); + + // Update GroupDefinition + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); + Either<GroupDefinition, ResponseFormat> actionResponse = businessLogic.updateGroupMetadata(componentId, user, groupUniqueId, componentTypeEnum, updatedGroup, true); + + if (actionResponse.isRight()) { + log.debug("failed to update GroupDefinition"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + GroupDefinition group = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(group); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Group Metadata"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Group Metadata"); + log.debug("update group metadata failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + /** + * Convert data to GroupDefinition object + * + * @param groupJson + * @return + */ + public Either<GroupDefinition, ResponseFormat> parseToGroup(String groupJson) { + try { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + GroupDefinition groupDefinition = gson.fromJson(groupJson, GroupDefinition.class); + return Either.left(groupDefinition); + } catch (Exception e) { + log.debug("Failed to parse json (group data) to GroupDefinition object"); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); + return Either.right(responseFormat); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java new file mode 100644 index 0000000000..e835c43e14 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java @@ -0,0 +1,320 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.List; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.InputsBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Input Catalog", description = "Input Servlet") +@Singleton +public class InputsServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(ProductServlet.class.getName()); + + @GET + @Path("/services/{componentId}/inputs") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Inputs only", httpMethod = "GET", notes = "Returns Inputs list", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getComponentInputs(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, @QueryParam("fromId") String fromName, + @QueryParam("amount") int amount, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + + InputsBusinessLogic businessLogic = getInputBL(context); + + Either<List<InputDefinition>, ResponseFormat> inputsResponse = businessLogic.getInputs(userId, componentId, fromName, amount); + if (inputsResponse.isRight()) { + log.debug("failed to get inputs {}", componentType); + return buildErrorResponse(inputsResponse.right().value()); + } + Object inputs = RepresentationUtils.toRepresentation(inputsResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), inputs); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Component Instance Inputs" + componentType); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Inputs" + componentType); + log.debug("getInputs failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/{componentType}/{componentId}/componentInstances/{instanceId}/{originComonentUid}/inputs") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Inputs only", httpMethod = "GET", notes = "Returns Inputs list", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getComponentInstanceInputs(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @PathParam("instanceId") final String instanceId, + @PathParam("originComonentUid") final String originComonentUid, @Context final HttpServletRequest request, @QueryParam("fromName") String fromName, @QueryParam("amount") int amount, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + InputsBusinessLogic businessLogic = getInputBL(context); + + Either<List<InputDefinition>, ResponseFormat> inputsResponse = businessLogic.getInputs(userId, originComonentUid, fromName, amount); + if (inputsResponse.isRight()) { + log.debug("failed to get component instance inputs {}", componentType); + return buildErrorResponse(inputsResponse.right().value()); + } + Object inputs = RepresentationUtils.toRepresentation(inputsResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), inputs); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Component Instance Inputs" + componentType); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Inputs" + componentType); + log.debug("getInputs failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/{componentType}/{componentId}/componentInstances/{instanceId}/{inputId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get properties", httpMethod = "GET", notes = "Returns properties list", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getInputPropertiesForComponentInstance(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @PathParam("instanceId") final String instanceId, + @PathParam("inputId") final String inputId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + InputsBusinessLogic businessLogic = getInputBL(context); + + Either<List<ComponentInstanceProperty>, ResponseFormat> inputPropertiesRes = businessLogic.getComponentInstancePropertiesByInputId(userId, instanceId, inputId); + if (inputPropertiesRes.isRight()) { + log.debug("failed to get properties of input: {}, with instance id: {}", inputId, instanceId); + return buildErrorResponse(inputPropertiesRes.right().value()); + } + Object properties = RepresentationUtils.toRepresentation(inputPropertiesRes.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get properties by input id {}, for component instance {} ", inputId, instanceId); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Properites by input id: " + inputId + " for instance with id: " + instanceId); + log.debug("getInputPropertiesForComponentInstance failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/{componentType}/{componentId}/inputs/{inputId}/inputs") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get inputs", httpMethod = "GET", notes = "Returns inputs list", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response getInputsForComponentInput(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @PathParam("inputId") final String inputId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + InputsBusinessLogic businessLogic = getInputBL(context); + + Either<List<ComponentInstanceInput>, ResponseFormat> inputsRes = businessLogic.getInputsForComponentInput(userId, componentId, inputId); + if (inputsRes.isRight()) { + log.debug("failed to get inputs of input: {}, with instance id: {}", inputId, componentId); + return buildErrorResponse(inputsRes.right().value()); + } + Object properties = RepresentationUtils.toRepresentation(inputsRes.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get inputs by input id {}, for component {} ", inputId, componentId); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get inputs by input id: " + inputId + " for component with id: " + componentId); + log.debug("getInputsForComponentInput failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + public Either<ComponentInstInputsMap, ResponseFormat> parseToComponentInstanceMap(String serviceJson, User user) { + return getComponentsUtils().convertJsonToObjectUsingObjectMapper(serviceJson, user, ComponentInstInputsMap.class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE); + } + + @POST + @Path("/{componentType}/{componentId}/create/inputs") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create inputs on service", httpMethod = "POST", notes = "Return inputs list", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response createMultipleInputs(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "ComponentIns Inputs Object to be created", required = true) String componentInstInputsMapObj) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + InputsBusinessLogic businessLogic = getInputBL(context); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Either<ComponentInstInputsMap, ResponseFormat> componentInstInputsMapRes = parseToComponentInstanceMap(componentInstInputsMapObj, modifier); + if (componentInstInputsMapRes.isRight()) { + log.debug("failed to parse componentInstInputsMap"); + response = buildErrorResponse(componentInstInputsMapRes.right().value()); + return response; + } + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + ComponentInstInputsMap componentInstInputsMap = componentInstInputsMapRes.left().value(); + + Either<List<InputDefinition>, ResponseFormat> inputPropertiesRes = businessLogic.createMultipleInputs(userId, componentId, componentTypeEnum, componentInstInputsMap, true, false); + if (inputPropertiesRes.isRight()) { + log.debug("failed to create inputs for service: {}", componentId); + return buildErrorResponse(inputPropertiesRes.right().value()); + } + Object properties = RepresentationUtils.toRepresentation(inputPropertiesRes.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create inputs for service with id: {}", componentId); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create inputs for service with id: " + componentId); + log.debug("createMultipleInputs failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @DELETE + @Path("/{componentType}/{componentId}/delete/{inputId}/input") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete input from service", httpMethod = "DELETE", notes = "Delete service input", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Input deleted"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Input not found") }) + public Response deleteInput ( + @PathParam("componentType") final String componentType, + @PathParam("componentId") final String componentId, + @PathParam("inputId") final String inputId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @ApiParam(value = "Service Input to be deleted", required = true) String componentInstInputsMapObj) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + InputsBusinessLogic businessLogic = getInputBL(context); + Either<InputDefinition, ResponseFormat> deleteInput = businessLogic.deleteInput(componentType, componentId, userId, inputId, true); + if (deleteInput.isRight()){ + ResponseFormat deleteResponseFormat = deleteInput.right().value(); + response = buildErrorResponse(deleteResponseFormat); + return response; + } + InputDefinition inputDefinition = deleteInput.left().value(); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), inputDefinition); + } catch (Exception e){ + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete input for service {} with id: {}", componentId, inputId); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete input for service + " + componentId + " + with id: " + inputId); + log.debug("Delete input failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + protected InputsBusinessLogic getInputBL(ServletContext context) { + + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + InputsBusinessLogic inputsBusinessLogic = webApplicationContext.getBean(InputsBusinessLogic.class); + return inputsBusinessLogic; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java new file mode 100644 index 0000000000..3f8bfd9149 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java @@ -0,0 +1,216 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.codehaus.jackson.map.ObjectMapper; +import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Lifecycle Actions Servlet", description = "Lifecycle Actions Servlet") +@Singleton +public class LifecycleServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(LifecycleServlet.class.getName()); + + @POST + @Path("/{componentCollection}/{componentId}/lifecycleState/{lifecycleOperation}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Change Resource lifecycle State", httpMethod = "POST", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource state changed"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 409, message = "Resource already exist") }) + public Response changeResourceState(@ApiParam(value = "LifecycleChangeInfo - relevant for checkin, failCertification, cancelCertification", required = false) String jsonChangeInfo, + @ApiParam(value = "validValues: resources / services / products", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME + "," + + ComponentTypeEnum.PRODUCT_PARAM_NAME) @PathParam(value = "componentCollection") final String componentCollection, + @ApiParam(allowableValues = "checkout, undoCheckout, checkin, certificationRequest, startCertification, failCertification, cancelCertification, certify", required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition, + @ApiParam(value = "id of component to be changed") @PathParam(value = "componentId") final String componentId, @Context final HttpServletRequest request, + @ApiParam(value = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + LifecycleBusinessLogic businessLogic = getLifecycleBL(context); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + Response response = null; + + // get modifier from graph + log.debug("get modifier properties"); + Either<User, Response> eitherGetUser = getUser(request, userId); + if (eitherGetUser.isRight()) { + return eitherGetUser.right().value(); + } + User user = eitherGetUser.left().value(); + + String resourceIdLower = componentId.toLowerCase(); + log.debug("perform {} operation to resource with id {} ", lifecycleTransition, resourceIdLower); + Either<LifeCycleTransitionEnum, Response> validateEnum = validateTransitionEnum(lifecycleTransition, user); + if (validateEnum.isRight()) { + return validateEnum.right().value(); + } + + LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction(); + + try { + if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) { + // Either<LifecycleChangeInfo, ResponseFormat > changeInfoResult + // = + // getComponentsUtils().convertJsonToObjectUsingObjectMapper(jsonChangeInfo, + // user, LifecycleChangeInfo.class, + // AuditingActionEnum.CHECKOUT_RESOURCE, null); + ObjectMapper mapper = new ObjectMapper(); + changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks()); + } + } + + catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject"); + BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject"); + log.debug("failed to convert from json {}", jsonChangeInfo, e); + ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(user, AuditingActionEnum.CHECKOUT_RESOURCE); + return buildErrorResponse(responseFormat); + } + + try { + LifeCycleTransitionEnum transitionEnum = validateEnum.left().value(); + ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(componentCollection); + // if (componentType == ComponentTypeEnum.RESOURCE){ + // Either<Resource, ResponseFormat> actionResponse = + // businessLogic.changeState(resourceIdLower, user, transitionEnum, + // changeInfo, false); + // + // if (actionResponse.isRight()){ + // log.info("failed to change resource state"); + // response = buildErrorResponse(actionResponse.right().value()); + // return response; + // } + // + // log.debug("change state successful !!!"); + // Object resource = + // RepresentationUtils.toRepresentation(actionResponse.left().value()); + // response = + // buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), + // resource); + // return response; + // + // } else if (componentType == ComponentTypeEnum.SERVICE || + // componentType == ComponentTypeEnum.PRODUCT){ + if (componentType != null) { + Either<? extends Component, ResponseFormat> actionResponse = businessLogic.changeComponentState(componentType, componentId, user, transitionEnum, changeInfo, false, true); + + if (actionResponse.isRight()) { + log.info("failed to change resource state"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + log.debug("change state successful !!!"); + Object value = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), value); + return response; + } else { + log.info("componentCollection \"{}\" is not valid. Supported componentCollection values are \"{}\", \"{}\" or \"{}\"", componentCollection, ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME, + ComponentTypeEnum.PRODUCT_PARAM_NAME); + ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, AuditingActionEnum.CHECKOUT_RESOURCE); + return buildErrorResponse(error); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Change Lifecycle State"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State"); + log.debug("change lifecycle state failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + private Either<LifeCycleTransitionEnum, Response> validateTransitionEnum(final String lifecycleTransition, User user) { + LifeCycleTransitionEnum transitionEnum = LifeCycleTransitionEnum.CHECKOUT; + try { + transitionEnum = LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition); + } catch (IllegalArgumentException e) { + log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString()); + ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, AuditingActionEnum.CHECKOUT_RESOURCE); + return Either.right(buildErrorResponse(error)); + } + return Either.left(transitionEnum); + } + + private LifecycleBusinessLogic getLifecycleBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + LifecycleBusinessLogic resourceBl = webApplicationContext.getBean(LifecycleBusinessLogic.class); + return resourceBl; + } + + protected Either<User, Response> getUser(final HttpServletRequest request, String userId) { + + Either<User, ActionStatus> eitherCreator = getUserAdminManager(request.getSession().getServletContext()).getUser(userId, false); + if (eitherCreator.isRight()) { + log.info("createResource method - user is not listed. userId={}", userId); + ResponseFormat errorResponse = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_INFORMATION); + User user = new User("", "", userId, "", null, null); + + getComponentsUtils().auditResource(errorResponse, user, null, "", "", AuditingActionEnum.CHECKOUT_RESOURCE, null); + return Either.right(buildErrorResponse(errorResponse)); + } + return Either.left(eitherCreator.left().value()); + + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ProductServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ProductServlet.java new file mode 100644 index 0000000000..f4ac921cb7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ProductServlet.java @@ -0,0 +1,311 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.ProductBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Product Catalog", description = "Product Servlet") +@Singleton +public class ProductServlet extends BeGenericServlet { + private static Logger log = LoggerFactory.getLogger(ProductServlet.class.getName()); + + @POST + @Path("/products") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create product", httpMethod = "POST", notes = "Returns created product", response = Product.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Product created"), @ApiResponse(code = 403, message = "Restricted operation / Empty USER_ID header"), @ApiResponse(code = 400, message = "Invalid/missing content"), + @ApiResponse(code = 409, message = "Product already exists / User not found / Wrong user role") }) + public Response createProduct(@ApiParam(value = "Product object to be created", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) @ApiParam(value = "USER_ID of product strategist user", required = true) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ProductBusinessLogic businessLogic = getProductBL(context); + Product product = RepresentationUtils.fromRepresentation(data, Product.class); + Either<Product, ResponseFormat> actionResponse = businessLogic.createProduct(product, modifier); + + if (actionResponse.isRight()) { + log.debug("Failed to create product"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Object result = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), result); + return response; + + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Product"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Product"); + log.debug("create product failed with error ", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @GET + @Path("/products/{productId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve product", httpMethod = "GET", notes = "Returns product according to productId", response = Product.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Product found"), @ApiResponse(code = 403, message = "Missing information"), @ApiResponse(code = 409, message = "Restricted operation"), + @ApiResponse(code = 500, message = "Internal Server Error"), @ApiResponse(code = 404, message = "Product not found"), }) + public Response getProductById(@PathParam("productId") final String productId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + ProductBusinessLogic businessLogic = getProductBL(context); + log.trace("get product with id {}", productId); + Either<Product, ResponseFormat> actionResponse = businessLogic.getProduct(productId, modifier); + + if (actionResponse.isRight()) { + log.debug("Failed to get product"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Object product = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), product); + + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Product"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Product"); + log.debug("get product failed with error ", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @GET + @Path("/products/productName/{productName}/productVersion/{productVersion}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Service", httpMethod = "GET", notes = "Returns product according to name and version", response = Product.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Product found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Product not found") }) + public Response getServiceByNameAndVersion(@PathParam("productName") final String productName, @PathParam("productVersion") final String productVersion, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ProductBusinessLogic businessLogic = getProductBL(context); + Either<Product, ResponseFormat> actionResponse = businessLogic.getProductByNameAndVersion(productName, productVersion, userId); + + if (actionResponse.isRight()) { + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Product product = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(product); + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get product by name and version"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get product by name and version"); + log.debug("get product failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @DELETE + @Path("/products/{productId}") + public Response deleteProduct(@PathParam("productId") final String productId, @Context final HttpServletRequest request) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + String userId = request.getHeader(Constants.USER_ID_HEADER); + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + ProductBusinessLogic businessLogic = getProductBL(context); + log.trace("delete product with id {}", productId); + Either<Product, ResponseFormat> actionResponse = businessLogic.deleteProduct(productId, modifier); + + if (actionResponse.isRight()) { + log.debug("Failed to delete product"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Object product = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), product); + return response; + + } catch (Throwable e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Resource"); + log.debug("delete resource failed with error ", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @PUT + @Path("/products/{productId}/metadata") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Product Metadata", httpMethod = "PUT", notes = "Returns updated product", response = Product.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Product Updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateProductMetadata(@PathParam("productId") final String productId, @ApiParam(value = "Product object to be Updated", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + Response response = null; + + try { + String productIdLower = productId.toLowerCase(); + ProductBusinessLogic businessLogic = getProductBL(context); + Product updatedProduct = RepresentationUtils.fromRepresentation(data, Product.class); + Either<Product, ResponseFormat> actionResponse = businessLogic.updateProductMetadata(productIdLower, updatedProduct, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to update product"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Product product = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(product); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Product Metadata"); + log.debug("update product metadata failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @GET + @Path("/products/validate-name/{productName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "validate product name", httpMethod = "GET", notes = "checks if the chosen product name is available ", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation") }) + public Response validateServiceName(@PathParam("productName") final String productName, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + Response response = null; + try { + ProductBusinessLogic businessLogic = getProductBL(context); + + Either<Map<String, Boolean>, ResponseFormat> actionResponse = businessLogic.validateProductNameExists(productName, userId); + + if (actionResponse.isRight()) { + log.debug("failed to get validate service name"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Validate Service Name"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Validate Product Name"); + log.debug("validate product name failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/PropertyServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/PropertyServlet.java new file mode 100644 index 0000000000..2c693c71a8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/PropertyServlet.java @@ -0,0 +1,562 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintSerialiser; +import org.openecomp.sdc.be.resources.data.EntryData; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Resource Property Servlet", description = "Resource Property Servlet") +@Singleton +public class PropertyServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(PropertyServlet.class.getName()); + + @POST + @Path("resources/{resourceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource Property", httpMethod = "POST", notes = "Returns created resource property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Resource property already exist") }) + public Response createProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "Resource property to be created", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + log.debug("data is {}", data); + + try { + // convert json to PropertyDefinition + Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(data); + if (either.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value()); + return buildErrorResponse(responseFormat); + } + Map<String, PropertyDefinition> properties = either.left().value(); + if (properties == null || properties.size() != 1) { + log.info("Property conetnt is invalid - {}", data); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } + Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next(); + String propertyName = entry.getKey(); + PropertyDefinition newPropertyDefinition = entry.getValue(); + + // create the new property + PropertyBusinessLogic businessLogic = getPropertyBL(context); + Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.createProperty(resourceId, propertyName, newPropertyDefinition, userId); + if (status.isRight()) { + log.info("Failed to create Property. Reason - ", status.right().value()); + return buildErrorResponse(status.right().value()); + } + EntryData<String, PropertyDefinition> property = status.left().value(); + String name = property.getKey(); + PropertyDefinition propertyDefinition = property.getValue(); + + log.debug("Property {} created successfully with id {}", name, propertyDefinition.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); + return buildOkResponse(responseFormat, propertyToJson(property)); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Property"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property"); + log.debug("create property failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + @GET + @Path("resources/{resourceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource Property", httpMethod = "GET", notes = "Returns property of resource", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Resource property not found") }) + public Response getProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "proerty id to get", required = true) @PathParam("propertyId") final String propertyId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + try { + + // + PropertyBusinessLogic businessLogic = getPropertyBL(context); + Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.getProperty(resourceId, propertyId, userId); + + if (status.isRight()) { + log.info("Failed to get Property. Reason - ", status.right().value()); + return buildErrorResponse(status.right().value()); + } + Entry<String, PropertyDefinition> property = status.left().value(); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, propertyToJson(property)); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Property"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property"); + log.debug("get property failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + @DELETE + @Path("resources/{resourceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Resource property not found") }) + public Response deleteProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + try { + + // delete the property + PropertyBusinessLogic businessLogic = getPropertyBL(context); + Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.deleteProperty(resourceId, propertyId, userId); + if (status.isRight()) { + log.debug("Failed to delete Property. Reason - ", status.right().value()); + return buildErrorResponse(status.right().value()); + } + EntryData<String, PropertyDefinition> property = status.left().value(); + String name = property.getKey(); + PropertyDefinition propertyDefinition = property.getValue(); + + log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); + return buildOkResponse(responseFormat, propertyToJson(property)); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Property"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property"); + log.debug("delete property failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + @PUT + @Path("resources/{resourceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource property updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "proerty id to update", required = true) @PathParam("propertyId") final String propertyId, @ApiParam(value = "Resource property to update", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + try { + // convert json to PropertyDefinition + Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(data); + if (either.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value()); + return buildErrorResponse(responseFormat); + } + Map<String, PropertyDefinition> properties = either.left().value(); + if (properties == null || properties.size() != 1) { + log.info("Property conetnt is invalid - {}", data); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } + Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next(); + PropertyDefinition newPropertyDefinition = entry.getValue(); + + // update property + PropertyBusinessLogic businessLogic = getPropertyBL(context); + Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.updateProperty(resourceId, propertyId, newPropertyDefinition, userId); + if (status.isRight()) { + log.info("Failed to update Property. Reason - ", status.right().value()); + return buildErrorResponse(status.right().value()); + } + EntryData<String, PropertyDefinition> property = status.left().value(); + PropertyDefinition propertyDefinition = property.getValue(); + + log.debug("Property id {} updated successfully ", propertyDefinition.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, propertyToJson(property)); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Property"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property"); + log.debug("update property failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + // private String propertyToJsonUi(Map.Entry<String, PropertyDefinition> + // property) { + // String name = property.getKey(); + // PropertyDefinition propertyDefinition = property.getValue(); + // JSONObject root = new JSONObject(); + // root.put("type", propertyDefinition.getType()); + // root.put("source", propertyDefinition.getDefaultValue()); + // root.put("name", name); + // root.put("description", propertyDefinition.getDescription()); + // root.put("uniqueId", propertyDefinition.getUniqueId()); + // return root.toString(); + // + // } + // + + // private Either<String ,ActionStatus> getJsonModel(String data){ + // Either<UiProperty,ActionStatus> uiPropertyEither = getUiProperty(data); + // if (uiPropertyEither.isRight()){ + // log.error("Property conetnt is invalid - {}",data); + // return Either.right(ActionStatus.INVALID_CONTENT); + // } + // UiProperty uiProperty = uiPropertyEither.left().value(); + // String json = convertUiPropertyToJsonModel(uiProperty); + // return Either.left(json); + // } + // + + // private String convertUiPropertyToJsonModel(UiProperty uiProperty) { + // JSONObject root = new JSONObject(); + // JSONObject propertyD = new JSONObject(); + // propertyD.put("type",uiProperty.getType()); + // propertyD.put("required",false); + // propertyD.put("description",uiProperty.getDescription()); + // propertyD.put("isPassword",false); + // propertyD.put("defaultValue",uiProperty.getSource()); + // JSONArray jsonArr = new JSONArray(); + // JSONArray jsonR = new JSONArray(); + // jsonR.add(100); + // jsonR.add(500); + // JSONObject o = new JSONObject(); + // o.put("inRange", jsonR); + // jsonArr.add(o); + // propertyD.put("constraints",jsonArr); + // root.put(uiProperty.getName(), propertyD); + // return root.toString(); + // } + + private Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String data) { + JSONParser parser = new JSONParser(); + JSONObject root; + try { + Map<String, PropertyDefinition> properties = new HashMap<String, PropertyDefinition>(); + root = (JSONObject) parser.parse(data); + + Set entrySet = root.entrySet(); + Iterator iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Entry next = (Entry) iterator.next(); + String propertyName = (String) next.getKey(); + JSONObject value = (JSONObject) next.getValue(); + String jsonString = value.toJSONString(); + Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class); + if (convertJsonToObject.isRight()) { + return Either.right(convertJsonToObject.right().value()); + } + PropertyDefinition propertyDefinition = convertJsonToObject.left().value(); + // PropertyDefinition propertyDefinition = + // gson.fromJson(jsonString , PropertyDefinition.class); + String uniqueId = UniqueIdBuilder.buildPropertyUniqueId("resourceId", (String) propertyName); + propertyDefinition.setUniqueId(uniqueId); + properties.put(propertyName, propertyDefinition); + } + + // Set keySet = root.keySet(); + // for (Object propertyName : keySet){ + // JSONObject val = (JSONObject) root.get(propertyName); + // String jsonString = val.toJSONString(); + // Either<PropertyDefinition,ActionStatus> convertJsonToObject = + // convertJsonToObject(jsonString, PropertyDefinition.class); + // if (convertJsonToObject.isRight()){ + // return Either.right(convertJsonToObject.right().value()); + // } + // PropertyDefinition propertyDefinition = + // convertJsonToObject.left().value(); + // //PropertyDefinition propertyDefinition = + // gson.fromJson(jsonString , PropertyDefinition.class); + // String uniqueId = + // UniqueIdBuilder.buildPropertyUniqueId("resourceId", + // (String)propertyName); + // propertyDefinition.setUniqueId(uniqueId); + // properties.put((String)propertyName,propertyDefinition); + // } + return Either.left(properties); + } catch (ParseException e) { + log.info("Property conetnt is invalid - {}", data); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } + + // private Either<Map<String,PropertyDefinition>,ActionStatus> + // getProperty(String data){ + // Type constraintType = new TypeToken<PropertyConstraint>() {}.getType(); + // PropertyConstraintDeserialiser propertyConstraintDeserialiser = new + // PropertyConstraintDeserialiser(); + // Gson gson = new + // GsonBuilder().registerTypeAdapter(constraintType,propertyConstraintDeserialiser).create(); + // JSONParser parser = new JSONParser(); + // JSONObject root; + // try { + // Map<String,PropertyDefinition> properties = new + // HashMap<String,PropertyDefinition>(); + // root = (JSONObject) parser.parse(data); + // Set keySet = root.keySet(); + // for (Object propertyName : keySet){ + // JSONObject val = (JSONObject) root.get(propertyName); + // String jsonString = val.toJSONString(); + // PropertyDefinition propertyDefinition = gson.fromJson(jsonString , + // PropertyDefinition.class); + // String uniqueId = UniqueIdBuilder.buildPropertyUniqueId("resourceId", + // (String)propertyName); + // propertyDefinition.setUniqueId(uniqueId); + // properties.put((String)propertyName,propertyDefinition); + // } + // return Either.left(properties); + // } catch (ParseException e) { + // log.error("Property conetnt is invalid - {}",data); + // return Either.right(ActionStatus.INVALID_CONTENT); + // } + // } + // + // private Either<UiProperty, ActionStatus> getUiProperty(String data) { + // try{ + // Gson gson = new Gson(); + // UiProperty uiProperty = gson.fromJson(data, UiProperty.class); + // return Either.left(uiProperty); + // }catch(JsonSyntaxException e){ + // log.warn("Problem create UiProperty from {}",data); + // log.debug("Problem create UiProperty from {}",data,e); + // return Either.right(ActionStatus.INVALID_CONTENT); + // } + // } + + private String propertyToJson(Map.Entry<String, PropertyDefinition> property) { + // Type constraintType = new TypeToken<PropertyConstraint>() + // {}.getType(); + // Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new + // PropertyConstraintDeserialiser()).create(); + JSONObject root = new JSONObject(); + String propertyName = property.getKey(); + PropertyDefinition propertyDefinition = property.getValue(); + // String jsonPropertyDefinition = gson.toJson(propertyDefinition); + // root.put(propertyName, jsonPropertyDefinition); + JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition); + root.put(propertyName, propertyDefinitionO); + propertyDefinition.getType(); + return root.toString(); + } + + private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) { + + Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition); + if (either.isRight()) { + return new JSONObject(); + } + String value = either.left().value(); + try { + JSONObject root = (JSONObject) new JSONParser().parse(value); + return root; + } catch (ParseException e) { + log.info("failed to convert input to json"); + log.debug("failed to convert to json", e); + return new JSONObject(); + } + + } + + // private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition + // propertyDefinition) { + // JSONObject root = new JSONObject(); + // root.put("type", propertyDefinition.getType()); + // root.put("required", propertyDefinition.isRequired()); + // root.put("defaultValue", propertyDefinition.getDefaultValue()); + // root.put("description", propertyDefinition.getDescription()); + // root.put("isPassword", propertyDefinition.isPassword()); + // List<PropertyConstraint> constraints = + // propertyDefinition.getConstraints(); + // for (PropertyConstraint p : constraints){ + // p.toString(); + // } + // root.put("constraints", propertyDefinition.getConstraints()); + // return root; + // } + + private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) { + T t = null; + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create(); + try { + log.trace("convert json to object. json=\n{}", data); + t = gson.fromJson(data, clazz); + if (t == null) { + log.info("object is null after converting from json"); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } catch (Exception e) { + // INVALID JSON + log.info("failed to convert from json"); + log.debug("failed to convert from json", e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + return Either.left(t); + } + + private <T> Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) { + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintSerialiser()).create(); + try { + log.trace("convert object to json. propertyDefinition={}", propertyDefinition.toString()); + String json = gson.toJson(propertyDefinition); + if (json == null) { + log.info("object is null after converting to json"); + return Either.right(ActionStatus.INVALID_CONTENT); + } + return Either.left(json); + } catch (Exception e) { + // INVALID JSON + log.info("failed to convert to json"); + log.debug("failed to convert fto json", e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + + } + + private PropertyBusinessLogic getPropertyBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + PropertyBusinessLogic propertytBl = webApplicationContext.getBean(PropertyBusinessLogic.class); + return propertytBl; + } + + // private class UiProperty{ + // String type; + // String source; + // String name; + // String description; + // public String getType() { + // return type; + // } + // public void setType(String type) { + // this.type = type; + // } + // public String getSource() { + // return source; + // } + // public void setSource(String source) { + // this.source = source; + // } + // public String getName() { + // return name; + // } + // public void setName(String name) { + // this.name = name; + // } + // public String getDescription() { + // return description; + // } + // public void setDescription(String description) { + // this.description = description; + // } + // + // } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RepresentationUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RepresentationUtils.java new file mode 100644 index 0000000000..565911eaa9 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RepresentationUtils.java @@ -0,0 +1,124 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.IOException; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig.Feature; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public class RepresentationUtils { + + private static Logger log = LoggerFactory.getLogger(RepresentationUtils.class.getName()); + + public static class ResourceRep { + + } + + /** + * Build Representation of given Object + * + * @param elementToRepresent + * @return + * @throws IOException + * @throws JsonGenerationException + * @throws JsonMappingException + */ + public static <T> Object toRepresentation(T elementToRepresent) throws IOException, JsonGenerationException, JsonMappingException { + + // return theResource; + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(Feature.FAIL_ON_EMPTY_BEANS, false); + mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); + return mapper.writeValueAsString(elementToRepresent); + } + + public static <T> T fromRepresentation(String json, Class<T> clazz) { + ObjectMapper mapper = new ObjectMapper(); + T object = null; + mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(Feature.FAIL_ON_EMPTY_BEANS, false); + mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); + try { + object = mapper.readValue(json, clazz); + } catch (Exception e) { + log.error("Error when parsing JSON of object of type {}", clazz.getSimpleName(), e); + } // return null in case of exception + + return object; + } + + public static ArtifactDefinition convertJsonToArtifactDefinition(String content, Class<ArtifactDefinition> clazz) { + + JsonObject jsonElement = new JsonObject(); + ArtifactDefinition resourceInfo = null; + try { + Gson gson = new Gson(); + jsonElement = gson.fromJson(content, jsonElement.getClass()); + JsonElement artifactGroupValue = jsonElement.get(Constants.ARTIFACT_GROUP_TYPE_FIELD); + if (artifactGroupValue != null && !artifactGroupValue.isJsonNull()) { + String groupValueUpper = artifactGroupValue.getAsString().toUpperCase(); + if (!ArtifactGroupTypeEnum.getAllTypes().contains(groupValueUpper)) { + StringBuilder sb = new StringBuilder(); + for (String value : ArtifactGroupTypeEnum.getAllTypes()) { + sb.append(value).append(", "); + } + log.debug("artifactGroupType is {}. valid values are: {}", groupValueUpper, sb.toString()); + return null; + } else { + jsonElement.remove(Constants.ARTIFACT_GROUP_TYPE_FIELD); + jsonElement.addProperty(Constants.ARTIFACT_GROUP_TYPE_FIELD, groupValueUpper); + } + } + String payload = null; + JsonElement artifactPayload = jsonElement.get(Constants.ARTIFACT_PAYLOAD_DATA); + if (artifactPayload != null && !artifactPayload.isJsonNull()) { + payload = artifactPayload.getAsString(); + } + jsonElement.remove(Constants.ARTIFACT_PAYLOAD_DATA); + resourceInfo = gson.fromJson(jsonElement, clazz); + resourceInfo.setPayloadData(payload); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeArtifactInformationInvalidError, "Artifact Upload / Update"); + BeEcompErrorManager.getInstance().logBeArtifactInformationInvalidError("Artifact Upload / Update"); + log.debug("Failed to convert the content {} to object. {}", content.substring(0, Math.min(50, content.length())), e); + } + + return resourceInfo; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementsServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementsServlet.java new file mode 100644 index 0000000000..e853ee4f7f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementsServlet.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonSyntaxException; +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +public class RequirementsServlet extends BeGenericServlet { + + private static Logger log = LoggerFactory.getLogger(RequirementsServlet.class.getName()); + + @PUT + @Path("resources/{resourceId}/requirements/{requirementId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Requirement", httpMethod = "PUT", notes = "Returns updated requirement", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource requirement updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateRequirement(@ApiParam(value = "resource id to update with new requirement", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "requirement id to update", required = true) @PathParam("requirementId") final String requirementId, @ApiParam(value = "Resource property to update", required = true) String requirementData, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + // Convert RequirementDefinition from JSON + // TODO: it's going to be another object, probably. This is placeholder + // for sake of JSON validation + // RequirementDefinition requirementDefinition; + ResponseFormat responseFormat; + try { + // requirementDefinition = gson.fromJson(requirementData, + // RequirementDefinition.class); + // ..... + + // TODO pass real entity + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), null); + } catch (JsonSyntaxException e) { + // INVALID JSON + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } catch (Exception e) { + log.debug("Unexpected error: {}", e); + responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceArtifactDownloadServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceArtifactDownloadServlet.java new file mode 100644 index 0000000000..673187b0a1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceArtifactDownloadServlet.java @@ -0,0 +1,188 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.api.ResourceUploadStatus; +import org.openecomp.sdc.be.impl.DownloadArtifactLogic; +import org.openecomp.sdc.be.info.ArtifactAccessInfo; +import org.openecomp.sdc.be.resources.api.IResourceUploader; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.jcabi.aspects.Loggable; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog/resources/available") +public class ResourceArtifactDownloadServlet extends ToscaDaoServlet { + + private static Logger log = LoggerFactory.getLogger(ResourceArtifactDownloadServlet.class.getName()); + + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + // @GET + // @Path("/{resourceName}/{resourceVersion}/artifacts") + // @Produces(MediaType.APPLICATION_JSON) + // public Response getResourceArtifactList(@PathParam("resourceName") final + // String resourceName, + // @PathParam("resourceVersion") final String resourceVersion, + // @Context final HttpServletRequest request){ + // + // + // String url = request.getMethod() + " " + request.getRequestURI(); + // log.info("Start handle request of {}", url); + // + // Response response = null; + // + // // get artifact list from dao + // IResourceUploader resourceDao = + // getResourceUploader(request.getSession().getServletContext()); + // if (resourceDao == null){ + // log.error("resource dao cannot be found"); + // response = buildResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, + // "Resource dao cannot be found"); + // return response; + // } + // Either<List<ESArtifactData>, ResourceUploadStatus> getArtifactsStatus = + // resourceDao.getArtifacts(resourceName, resourceVersion); + // + // response = + // getLogic(request.getSession().getServletContext()).createArtifactListResponse(resourceName, + // getArtifactsStatus, getServletPath(request)); + // + // log.info("Finish handle request of {} | result = {}", url, response.getStatus() ); + // return response; + // + // } + + @GET + @Path("/{resourceName}/{resourceVersion}/artifacts/{artifactName}") + // @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response getResourceArtifactByName(@PathParam("resourceName") final String resourceName, @PathParam("resourceVersion") final String resourceVersion, @PathParam("artifactName") final String artifactName, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + Response response = null; + try { + // get the artifact data + String artifactId = String.format(Constants.ARTIFACT_ID_FORMAT, resourceName, resourceVersion, artifactName); + + IResourceUploader resouceUploader = getResourceUploader(request.getSession().getServletContext()); + if (resouceUploader == null) { + return buildResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, ""); + + } + Either<ESArtifactData, ResourceUploadStatus> getArtifactStatus = resouceUploader.getArtifact(artifactId); + + DownloadArtifactLogic logic = getLogic(request.getSession().getServletContext()); + if (logic == null) { + return buildResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, ""); + + } + response = logic.downloadArtifact(resourceName, resourceVersion, artifactName, getArtifactStatus, artifactId); + + log.info("Finish handle request of {} | result = {}", url, response.getStatus()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Resource Artifact By Name"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Resource Artifact By Name"); + log.debug("getResourceArtifactByName failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @GET + @Path("/{resourceName}/{resourceVersion}/artifacts/{artifactName}/metadata") + @Produces(MediaType.APPLICATION_JSON) + public Response getResourceArtifactMetadata(@PathParam("resourceName") final String resourceName, @PathParam("resourceVersion") final String resourceVersion, @PathParam("artifactName") final String artifactName, + @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + Response response = null; + try { + IResourceUploader resourceDao = getResourceUploader(request.getSession().getServletContext()); + if (resourceDao == null) { + log.error("resource dao cannot be found"); + response = buildResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Resource dao cannot be found"); + return response; + } + + String artifactId = String.format(Constants.ARTIFACT_ID_FORMAT, resourceName, resourceVersion, artifactName); + Either<ESArtifactData, ResourceUploadStatus> getArtifactStatus = resourceDao.getArtifact(artifactId); + + if (getArtifactStatus.isRight()) { + ResourceUploadStatus status = getArtifactStatus.right().value(); + if (status == ResourceUploadStatus.COMPONENT_NOT_EXIST) { + response = Response.status(HttpStatus.SC_NOT_FOUND).build(); + log.debug("Could not find artifact for with id: {}", artifactId); + } else { + response = Response.status(HttpStatus.SC_NO_CONTENT).build(); + log.debug("Could not find artifact for with id: {}", artifactId); + } + return response; + } else { + ESArtifactData artifactData = getArtifactStatus.left().value(); + log.debug("found artifact with id: {}", artifactId); + ArtifactAccessInfo artifactInfo = new ArtifactAccessInfo(artifactData); + String artifactDataJson = gson.toJson(artifactInfo); + response = Response.status(HttpStatus.SC_OK).entity(artifactDataJson).type(MediaType.APPLICATION_JSON_TYPE).build(); + + log.info("Finish handle request of {} | result = {}", url, response.getStatus()); + return response; + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Resource Artifact Metadata"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Resource Artifact Metadata"); + log.debug("getResourceArtifactMetadata failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + + } + + @Override + public Logger getLogger() { + return log; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceUploadServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceUploadServlet.java new file mode 100644 index 0000000000..5cd765abe0 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceUploadServlet.java @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.File; + +import javax.annotation.Resource; +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.openecomp.sdc.be.components.impl.ResourceImportManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.UploadResourceInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +/** + * Root resource (exposed at "/" path) + */ +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog/upload") +@Api(value = "Resources Catalog Upload", description = "Upload resource yaml") +@Singleton +public class ResourceUploadServlet extends AbstractValidationsServlet { + + private static Logger log = LoggerFactory.getLogger(ResourceUploadServlet.class.getName()); + public static final String NORMATIVE_TYPE_RESOURCE = "multipart"; + public static final String USER_TYPE_RESOURCE = "user-resource"; + public static final String USER_TYPE_RESOURCE_UI_IMPORT = "user-resource-ui-import"; + + public enum ResourceAuthorityTypeEnum { + NORMATIVE_TYPE_BE(NORMATIVE_TYPE_RESOURCE, true, false), USER_TYPE_BE(USER_TYPE_RESOURCE, true, true), USER_TYPE_UI(USER_TYPE_RESOURCE_UI_IMPORT, false, true); + + private String urlPath; + private boolean isBackEndImport, isUserTypeResource; + + public static ResourceAuthorityTypeEnum findByUrlPath(String urlPath) { + ResourceAuthorityTypeEnum found = null; + for (ResourceAuthorityTypeEnum curr : ResourceAuthorityTypeEnum.values()) { + if (curr.getUrlPath().equals(urlPath)) { + found = curr; + break; + } + } + return found; + } + + private ResourceAuthorityTypeEnum(String urlPath, boolean isBackEndImport, boolean isUserTypeResource) { + this.urlPath = urlPath; + this.isBackEndImport = isBackEndImport; + this.isUserTypeResource = isUserTypeResource; + } + + public String getUrlPath() { + return urlPath; + } + + public boolean isBackEndImport() { + return isBackEndImport; + } + + public boolean isUserTypeResource() { + return isUserTypeResource; + } + } + + @Resource + private ResourceImportManager resourceImportManager; + + @POST + @Path("/{resourceAuthority}") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource from yaml", httpMethod = "POST", notes = "Returns created resource", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Resource already exist") }) + public Response uploadMultipart( + @ApiParam(value = "validValues: normative-resource / user-resource", allowableValues = NORMATIVE_TYPE_RESOURCE + "," + USER_TYPE_RESOURCE + "," + + USER_TYPE_RESOURCE_UI_IMPORT) @PathParam(value = "resourceAuthority") final String resourceAuthority, + @ApiParam("FileInputStream") @FormDataParam("resourceZip") File file, @ApiParam("ContentDisposition") @FormDataParam("resourceZip") FormDataContentDisposition contentDispositionHeader, + @ApiParam("resourceMetadata") @FormDataParam("resourceMetadata") String resourceInfoJsonString, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + // updateResourse Query Parameter if false checks if already exist + @DefaultValue("true") @QueryParam("createNewVersion") boolean createNewVersion) { + + init(request.getSession().getServletContext()); + try { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + Wrapper<User> userWrapper = new Wrapper<>(); + Wrapper<UploadResourceInfo> uploadResourceInfoWrapper = new Wrapper<>(); + Wrapper<String> yamlStringWrapper = new Wrapper<>(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // When we get an errorResponse it will be filled into the + // responseWrapper + validateAuthorityType(responseWrapper, resourceAuthority); + + ResourceAuthorityTypeEnum resourceAuthorityEnum = ResourceAuthorityTypeEnum.findByUrlPath(resourceAuthority); + + commonGeneralValidations(responseWrapper, userWrapper, uploadResourceInfoWrapper, resourceAuthorityEnum, userId, resourceInfoJsonString); + + fillPayload(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), resourceInfoJsonString, resourceAuthorityEnum, file); + + // PayLoad Validations + commonPayloadValidations(responseWrapper, yamlStringWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement()); + + specificResourceAuthorityValidations(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), request, resourceInfoJsonString, resourceAuthorityEnum); + + if (responseWrapper.isEmpty()) { + handleImport(responseWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement(), yamlStringWrapper.getInnerElement(), resourceAuthorityEnum, createNewVersion, null); + } + + return responseWrapper.getInnerElement(); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Upload Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Upload Resource"); + log.debug("upload resource failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + /********************************************************************************************************************/ + + private void init(ServletContext context) { + init(log); + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + resourceImportManager = webApplicationContext.getBean(ResourceImportManager.class); + resourceImportManager.init(context); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java new file mode 100644 index 0000000000..e3d39610a8 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java @@ -0,0 +1,692 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.http.HttpStatus; +import org.json.JSONObject; +import org.openecomp.sdc.be.components.impl.CsarValidationUtils; +import org.openecomp.sdc.be.components.impl.ImportUtils; +import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; +import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.ResourceMetadataDefinition; +import org.openecomp.sdc.be.model.UploadResourceInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.servlets.ResourceUploadServlet.ResourceAuthorityTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Resources Catalog", description = "Resources Servlet") +@Singleton +public class ResourcesServlet extends AbstractValidationsServlet { + + private static Logger log = LoggerFactory.getLogger(ResourcesServlet.class.getName()); + + @POST + @Path("/resources") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource", httpMethod = "POST", notes = "Returns created resource", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Resource already exist") }) + public Response createResource(@ApiParam(value = "Resource object to be created", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + userId = (userId != null) ? userId : request.getHeader(Constants.USER_ID_HEADER); + init(log); + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + // UI Import + if (isUIImport(data)) { + performUIImport(responseWrapper, data, request, userId, null); + } + // UI Create + else { + + ResourceBusinessLogic businessLogic = getResourceBL(context); + + Either<Resource, ResponseFormat> convertResponse = parseToResource(data, modifier); + if (convertResponse.isRight()) { + log.debug("failed to parse resource"); + response = buildErrorResponse(convertResponse.right().value()); + return response; + } + + Resource resource = convertResponse.left().value(); + Either<Resource, ResponseFormat> actionResponse = businessLogic.createResource(resource, modifier, null, null); + + if (actionResponse.isRight()) { + log.debug("failed to create resource"); + response = buildErrorResponse(actionResponse.right().value()); + } else { + Object representation = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation); + } + responseWrapper.setInnerElement(response); + } + + return responseWrapper.getInnerElement(); + + // return response; + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Resource"); + log.debug("create resource failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + private boolean isUIImport(String data) { + boolean isUIImport; + try { + JSONObject json = new JSONObject(data); + String payloadName = json.getString(ImportUtils.Constants.UI_JSON_PAYLOAD_NAME); + isUIImport = payloadName != null && !payloadName.isEmpty(); + } catch (Exception e) { + log.debug("failed to parse json sent from client, json:{}", data); + isUIImport = false; + } + return isUIImport; + } + + private void performUIImport(Wrapper<Response> responseWrapper, String data, final HttpServletRequest request, String userId, String resourceUniqueId) throws FileNotFoundException { + + Wrapper<User> userWrapper = new Wrapper<>(); + Wrapper<UploadResourceInfo> uploadResourceInfoWrapper = new Wrapper<>(); + Wrapper<String> yamlStringWrapper = new Wrapper<>(); + String resourceInfoJsonString = data; + + ResourceAuthorityTypeEnum resourceAuthorityEnum = ResourceAuthorityTypeEnum.USER_TYPE_UI; + + commonGeneralValidations(responseWrapper, userWrapper, uploadResourceInfoWrapper, resourceAuthorityEnum, userId, resourceInfoJsonString); + + // TODO suspect next line is unnecessary + userWrapper.getInnerElement(); + if (!CsarValidationUtils.isCsarPayloadName(uploadResourceInfoWrapper.getInnerElement().getPayloadName())) { + fillPayload(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), resourceInfoJsonString, resourceAuthorityEnum, null); + + // PayLoad Validations + commonPayloadValidations(responseWrapper, yamlStringWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement()); + } + specificResourceAuthorityValidations(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), request, resourceInfoJsonString, resourceAuthorityEnum); + + if (responseWrapper.isEmpty()) { + handleImport(responseWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement(), yamlStringWrapper.getInnerElement(), resourceAuthorityEnum, true, resourceUniqueId); + } + } + + public Either<Resource, ResponseFormat> parseToResource(String resourceJson, User user) { + return getComponentsUtils().convertJsonToObjectUsingObjectMapper(resourceJson, user, Resource.class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.RESOURCE); + } + + public Either<Resource, ResponseFormat> parseToLightResource(String resourceJson, User user) { + Either<Resource, ResponseFormat> ret = getComponentsUtils().convertJsonToObjectUsingObjectMapper(resourceJson, user, Resource.class, AuditingActionEnum.UPDATE_RESOURCE_METADATA, ComponentTypeEnum.RESOURCE); + if (ret.isLeft()) {// drop unwanted data (sent from UI in update flow) + ret.left().value().setRequirements(null); + ret.left().value().setCapabilities(null); + } + return ret; + } + + @DELETE + @Path("/resources/{resourceId}") + public Response deleteResource(@PathParam("resourceId") final String resourceId, @Context final HttpServletRequest request) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + String userId = request.getHeader(Constants.USER_ID_HEADER); + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + String resourceIdLower = resourceId.toLowerCase(); + ResourceBusinessLogic businessLogic = getResourceBL(context); + ResponseFormat actionResponse = businessLogic.deleteResource(resourceIdLower, modifier); + + if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) { + log.debug("failed to delete resource"); + response = buildErrorResponse(actionResponse); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Resource"); + log.debug("delete resource failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @DELETE + @Path("/resources/{resourceName}/{version}") + public Response deleteResourceByNameAndVersion(@PathParam("resourceName") final String resourceName, @PathParam("version") final String version, @Context final HttpServletRequest request) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + String userId = request.getHeader(Constants.USER_ID_HEADER); + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + ResourceBusinessLogic businessLogic = getResourceBL(context); + ResponseFormat actionResponse = businessLogic.deleteResourceByNameAndVersion(resourceName, version, modifier); + + if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) { + log.debug("failed to delete resource"); + response = buildErrorResponse(actionResponse); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Resource"); + log.debug("delete resource failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/resources/{resourceId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Resource", httpMethod = "GET", notes = "Returns resource according to resourceId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Resource not found") }) + public Response getResourceById(@PathParam("resourceId") final String resourceId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + String resourceIdLower = resourceId.toLowerCase(); + ResourceBusinessLogic businessLogic = getResourceBL(context); + log.trace("get resource with id {}", resourceId); + Either<Resource, ResponseFormat> actionResponse = businessLogic.getResource(resourceIdLower, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to get resource"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + Object resource = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resource); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Resource"); + log.debug("get resource failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @GET + @Path("/resources/resourceName/{resourceName}/resourceVersion/{resourceVersion}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Resource by name and version", httpMethod = "GET", notes = "Returns resource according to resourceId", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Resource not found") }) + public Response getResourceByNameAndVersion(@PathParam("resourceName") final String resourceName, @PathParam("resourceVersion") final String resourceVersion, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + Response response = null; + try { + ResourceBusinessLogic businessLogic = getResourceBL(context); + Either<List<Resource>, ResponseFormat> actionResponse = businessLogic.getResourceByNameAndVersion(resourceName, resourceVersion, userId); + if (actionResponse.isRight()) { + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + Object resource = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resource); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Resource by name and version"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Resource by name and version"); + log.debug("get resource failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @GET + @Path("/resources/validate-name/{resourceName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "validate resource name", httpMethod = "GET", notes = "checks if the chosen resource name is available ", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource found"), @ApiResponse(code = 403, message = "Restricted operation") }) + public Response validateResourceName(@PathParam("resourceName") final String resourceName, @QueryParam("subtype") String resourceType, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + Response response = null; + try { + ResourceBusinessLogic businessLogic = getResourceBL(context); + + if (resourceType != null && !ResourceTypeEnum.contains(resourceType)) { + log.debug("invalid resource type received"); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + return response; + + } + ResourceTypeEnum typeEnum = null; + if (resourceType != null) { + typeEnum = ResourceTypeEnum.valueOf(resourceType); + } + Either<Map<String, Boolean>, ResponseFormat> actionResponse = businessLogic.validateResourceNameExists(resourceName, typeEnum, userId); + + if (actionResponse.isRight()) { + log.debug("failed to validate resource name"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Validate Resource Name"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Validate Resource Name"); + log.debug("validate resource name failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/resources/certified/abstract") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getCertifiedAbstractResources(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + // TODO: any validations??? + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + try { + + ResourceBusinessLogic businessLogic = getResourceBL(context); + + Either<List<Resource>, ResponseFormat> actionResponse = businessLogic.getAllCertifiedResources(true, HighestFilterEnum.HIGHEST_ONLY, userId); + + if (actionResponse.isRight()) { + log.debug("failed to get all abstract resources"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + Object resources = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resources); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Certified Abstract Resources"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Abstract Resources"); + log.debug("getCertifiedAbstractResources failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/resources/certified/notabstract") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getCertifiedNotAbstractResources(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + // TODO: any vlidations??? + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response = null; + + try { + + ResourceBusinessLogic businessLogic = getResourceBL(context); + + Either<List<Resource>, ResponseFormat> actionResponse = businessLogic.getAllCertifiedResources(false, HighestFilterEnum.ALL, userId); + + if (actionResponse.isRight()) { + log.debug("failed to get all non abstract resources"); + return buildErrorResponse(actionResponse.right().value()); + } + Object resources = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resources); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Certified Non Abstract Resources"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Non Abstract Resources"); + log.debug("getCertifiedNotAbstractResources failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + + } + + @PUT + @Path("/resources/{resourceId}/metadata") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Metadata", httpMethod = "PUT", notes = "Returns updated resource metadata", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource metadata updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content") }) + public Response updateResourceMetadata(@PathParam("resourceId") final String resourceId, @ApiParam(value = "Resource metadata to be updated", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + ResourceBusinessLogic businessLogic = getResourceBL(context); + String resourceIdLower = resourceId.toLowerCase(); + Either<Resource, ResponseFormat> updateInfoResource = getComponentsUtils().convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class, AuditingActionEnum.UPDATE_RESOURCE_METADATA, ComponentTypeEnum.RESOURCE); + if (updateInfoResource.isRight()) { + log.debug("failed to parse resource metadata"); + response = buildErrorResponse(updateInfoResource.right().value()); + return response; + } + Either<Resource, ResponseFormat> actionResponse = businessLogic.updateResourceMetadata(resourceIdLower, + updateInfoResource.left().value(), null, modifier, false); + + if (actionResponse.isRight()) { + log.debug("failed to update resource metadata"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + Object resource = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resource); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Resource Metadata"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource Metadata"); + log.debug("Update Resource Metadata failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @PUT + @Path("/resources/{resourceId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource", httpMethod = "PUT", notes = "Returns updated resource", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Resource already exist") }) + public Response updateResource(@ApiParam(value = "Resource object to be updated", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @PathParam(value = "resourceId") String resourceId) { + + userId = (userId != null) ? userId : request.getHeader(Constants.USER_ID_HEADER); + init(log); + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + + Wrapper<Response> responseWrapper = new Wrapper<>(); + // UI Import + if (isUIImport(data)) { + performUIImport(responseWrapper, data, request, userId, resourceId); + } else { + + ResourceBusinessLogic businessLogic = getResourceBL(context); + + Either<Resource, ResponseFormat> convertResponse = parseToLightResource(data, modifier); + if (convertResponse.isRight()) { + log.debug("failed to parse resource"); + response = buildErrorResponse(convertResponse.right().value()); + return response; + } + + Resource resource = convertResponse.left().value(); + Either<Resource, ResponseFormat> actionResponse = businessLogic.validateAndUpdateResourceFromCsar(resource, modifier, null, null, resourceId); + + if (actionResponse.isRight()) { + log.debug("failed to update resource"); + response = buildErrorResponse(actionResponse.right().value()); + } else { + Object representation = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation); + } + responseWrapper.setInnerElement(response); + } + + return responseWrapper.getInnerElement(); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Resource"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource"); + log.debug("update resource failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + /* + * @GET + * + * @Path("/resources/latestversion/notabstract") + * + * @Consumes(MediaType.APPLICATION_JSON) + * + * @Produces(MediaType.APPLICATION_JSON) public Response getLatestVersionNotAbstractResources(@Context final HttpServletRequest request) { //TODO: any vlidations??? ServletContext context = request.getSession().getServletContext(); + * + * String url = request.getMethod() + " " + request.getRequestURI(); log.debug("(get) Start handle request of {}", url); Response response=null; + * + * try { + * + * ResourceBusinessLogic businessLogic = getResourceBL(context); + * + * Either<List<Resource>, ResponseFormat> actionResponse = businessLogic.getLatestVersionResources(false, HighestFilterEnum.HIGHEST_ONLY); + * + * + * if (actionResponse.isRight()){ log.debug( "failed to get all non abstract resources"); return buildErrorResponse(actionResponse.right().value()); } return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), + * actionResponse.left().value()); + * + * } catch (Exception e){ BeEcompErrorManager.getInstance().processEcompError(EcompErrorName. BeRestApiGeneralError, "Get Certified Non Abstract Resources"); log.debug("getCertifiedNotAbstractResources failed with exception", e); response = + * buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus. GENERAL_ERROR)); return response; + * + * } } + */ + public static List<PropertyDefinition> convertMapToList(Map<String, PropertyDefinition> properties) { + if (properties == null) { + return null; + } + + List<PropertyDefinition> definitions = new ArrayList<>(); + for (Entry<String, PropertyDefinition> entry : properties.entrySet()) { + String name = entry.getKey(); + PropertyDefinition propertyDefinition = entry.getValue(); + propertyDefinition.setName(name); + definitions.add(propertyDefinition); + } + + return definitions; + } + + @GET + @Path("/resources/csar/{csaruuid}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource", httpMethod = "POST", notes = "Returns resource created from csar uuid", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource retrieced"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response getResourceFromCsar(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @PathParam(value = "csaruuid") String csarUUID) { + + init(log); + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // retrieve user details + userId = (userId != null) ? userId : request.getHeader(Constants.USER_ID_HEADER); + User user = new User(); + user.setUserId(userId); + + log.debug("user id is {}", userId); + + Response response = null; + + try { + + ResourceBusinessLogic businessLogic = getResourceBL(context); + + Either<Resource, ResponseFormat> eitherResource = businessLogic.getLatestResourceFromCsarUuid(csarUUID, user); + + // validate response + if (eitherResource.isRight()) { + log.debug("failed to get resource from csarUuid : {}", csarUUID); + // response = + // buildErrorResponse(eitherResource.right().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), eitherResource.right().value()); + } else { + Object representation = RepresentationUtils.toRepresentation(eitherResource.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation); + } + + return response; + + } catch (Exception e) { + log.debug("get resource by csar failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java new file mode 100644 index 0000000000..7e7068f5d7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java @@ -0,0 +1,728 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.Configuration; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Service Catalog", description = "Service Servlet") +@Singleton +public class ServiceServlet extends AbstractValidationsServlet { + + private static Logger log = LoggerFactory.getLogger(ServiceServlet.class.getName()); + + @POST + @Path("/services") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Service", httpMethod = "POST", notes = "Returns created service", response = Service.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Service created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Service already exist") }) + public Response createService(@ApiParam(value = "Service object to be created", required = true) String data, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + Either<Service, ResponseFormat> convertResponse = parseToService(data, modifier); + if (convertResponse.isRight()) { + log.debug("failed to parse service"); + response = buildErrorResponse(convertResponse.right().value()); + return response; + } + + Service service = convertResponse.left().value(); + Either<Service, ResponseFormat> actionResponse = businessLogic.createService(service, modifier); + + if (actionResponse.isRight()) { + log.debug("Failed to create service"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Object result = RepresentationUtils.toRepresentation(actionResponse.left().value()); + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), result); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Service"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Service"); + log.debug("create service failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + public Either<Service, ResponseFormat> parseToService(String serviceJson, User user) { + return getComponentsUtils().convertJsonToObjectUsingObjectMapper(serviceJson, user, Service.class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE); + } + + @GET + @Path("/services/validate-name/{serviceName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "validate service name", httpMethod = "GET", notes = "checks if the chosen service name is available ", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation") }) + public Response validateServiceName(@PathParam("serviceName") final String serviceName, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + + Either<Map<String, Boolean>, ResponseFormat> actionResponse = businessLogic.validateServiceNameExists(serviceName, userId); + + if (actionResponse.isRight()) { + log.debug("failed to get validate service name"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value()); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Validate Service Name"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Validate Service Name"); + log.debug("validate service name failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/audit-records/{componentType}/{componentUniqueId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "get component audit records", httpMethod = "GET", notes = "get audit records for a service or a resource", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation") }) + public Response getComponentAuditRecords(@PathParam("componentType") final String componentType, @PathParam("componentUniqueId") final String componentUniqueId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + init(log); + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + Wrapper<Response> responseWrapper = new Wrapper<Response>(); + Wrapper<String> uuidWrapper = new Wrapper<String>(); + Wrapper<String> versionWrapper = new Wrapper<String>(); + Wrapper<User> userWrapper = new Wrapper<User>(); + Wrapper<ComponentTypeEnum> componentWrapper = new Wrapper<ComponentTypeEnum>(); + try { + validateUserExist(responseWrapper, userWrapper, userId); + + if (responseWrapper.isEmpty()) { + validateComponentType(responseWrapper, componentWrapper, componentType); + } + + if (responseWrapper.isEmpty()) { + fillUUIDAndVersion(responseWrapper, uuidWrapper, versionWrapper, userWrapper.getInnerElement(), componentWrapper.getInnerElement(), componentUniqueId, context); + } + + if (responseWrapper.isEmpty()) { + Either<List<Map<String, Object>>, ResponseFormat> eitherServiceAudit = getServiceBL(context).getComponentAuditRecords(versionWrapper.getInnerElement(), uuidWrapper.getInnerElement(), userId); + + if (eitherServiceAudit.isRight()) { + Response errorResponse = buildErrorResponse(eitherServiceAudit.right().value()); + responseWrapper.setInnerElement(errorResponse); + } else { + List<Map<String, Object>> auditRecords = eitherServiceAudit.left().value(); + Response okResponse = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), auditRecords); + responseWrapper.setInnerElement(okResponse); + + } + } + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Validate Service Name"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Validate Service Name"); + log.debug("get Service Audit Records failed with exception", e); + Response errorResponse = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + responseWrapper.setInnerElement(errorResponse); + } + return responseWrapper.getInnerElement(); + } + + private void fillUUIDAndVersion(Wrapper<Response> responseWrapper, Wrapper<String> uuidWrapper, Wrapper<String> versionWrapper, User user, final ComponentTypeEnum componentTypeEnum, final String componentUniqueId, ServletContext context) { + + if (componentTypeEnum == ComponentTypeEnum.RESOURCE) { + Either<Resource, ResponseFormat> eitherResource = getResourceBL(context).getResource(componentUniqueId, user); + if (eitherResource.isLeft()) { + uuidWrapper.setInnerElement(eitherResource.left().value().getUUID()); + versionWrapper.setInnerElement(eitherResource.left().value().getVersion()); + } else { + responseWrapper.setInnerElement(buildErrorResponse(eitherResource.right().value())); + } + + } else { + Either<Service, ResponseFormat> eitherService = getServiceBL(context).getService(componentUniqueId, user); + if (eitherService.isLeft()) { + uuidWrapper.setInnerElement(eitherService.left().value().getUUID()); + versionWrapper.setInnerElement(eitherService.left().value().getVersion()); + } else { + responseWrapper.setInnerElement(buildErrorResponse(eitherService.right().value())); + + } + } + } + + @DELETE + @Path("/services/{serviceId}") + public Response deleteService(@PathParam("serviceId") final String serviceId, @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + String userId = request.getHeader(Constants.USER_ID_HEADER); + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + String serviceIdLower = serviceId.toLowerCase(); + ServiceBusinessLogic businessLogic = getServiceBL(context); + ResponseFormat actionResponse = businessLogic.deleteService(serviceIdLower, modifier); + + if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) { + log.debug("failed to delete service"); + response = buildErrorResponse(actionResponse); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Service"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Service"); + log.debug("delete service failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @DELETE + @Path("/services/{serviceName}/{version}") + public Response deleteServiceByNameAndVersion(@PathParam("serviceName") final String serviceName, @PathParam("version") final String version, @Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + String userId = request.getHeader(Constants.USER_ID_HEADER); + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + ResponseFormat actionResponse = businessLogic.deleteServiceByNameAndVersion(serviceName, version, modifier); + + if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) { + log.debug("failed to delete service"); + response = buildErrorResponse(actionResponse); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Delete Service"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Service"); + log.debug("delete service failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @PUT + @Path("/services/{serviceId}/metadata") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Service Metadata", httpMethod = "PUT", notes = "Returns updated service", response = Service.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service Updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updateServiceMetadata(@PathParam("serviceId") final String serviceId, @ApiParam(value = "Service object to be Updated", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + + try { + String serviceIdLower = serviceId.toLowerCase(); + ServiceBusinessLogic businessLogic = getServiceBL(context); + + Either<Service, ResponseFormat> convertResponse = parseToService(data, modifier); + if (convertResponse.isRight()) { + log.debug("failed to parse service"); + response = buildErrorResponse(convertResponse.right().value()); + return response; + } + Service updatedService = convertResponse.left().value(); + Either<Service, ResponseFormat> actionResponse = businessLogic.updateServiceMetadata(serviceIdLower, updatedService, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to update service"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Service service = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(service); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Service Metadata"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Service Metadata"); + log.debug("update service metadata failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + @GET + @Path("/services/{serviceId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Service", httpMethod = "GET", notes = "Returns service according to serviceId", response = Service.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Service not found") }) + public Response getServiceById(@PathParam("serviceId") final String serviceId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + String serviceIdLower = serviceId.toLowerCase(); + ServiceBusinessLogic businessLogic = getServiceBL(context); + log.debug("get service with id {}", serviceId); + Either<Service, ResponseFormat> actionResponse = businessLogic.getService(serviceIdLower, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to get service"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Service service = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(service); + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Service"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Service"); + log.debug("get service failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @GET + @Path("/services/serviceName/{serviceName}/serviceVersion/{serviceVersion}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve Service", httpMethod = "GET", notes = "Returns service according to name and version", response = Service.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Service not found") }) + public Response getServiceByNameAndVersion(@PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + Either<Service, ResponseFormat> actionResponse = businessLogic.getServiceByNameAndVersion(serviceName, serviceVersion, userId); + + if (actionResponse.isRight()) { + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + + Service service = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(service); + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Service by name and version"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Service by name and version"); + log.debug("get service failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + + } + } + + @POST + @Path("/services/{serviceId}/distribution-state/{state}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Service Distribution State", httpMethod = "POST", notes = "service with the changed distribution status") + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service distribution state changed"), @ApiResponse(code = 409, message = "Restricted operation"), @ApiResponse(code = 403, message = "Service is not available for distribution"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), @ApiResponse(code = 404, message = "Requested service was not found"), @ApiResponse(code = 500, message = "Internal Server Error. Please try again later.") }) + public Response updateServiceDistributionState(@ApiParam(value = "DistributionChangeInfo - get comment out of body", required = true) LifecycleChangeInfoWithAction jsonChangeInfo, @PathParam("serviceId") final String serviceId, + @ApiParam(allowableValues = "approve, reject", required = true) @PathParam("state") final String state, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + Either<Service, ResponseFormat> actionResponse = businessLogic.changeServiceDistributionState(serviceId, state, jsonChangeInfo, modifier); + + if (actionResponse.isRight()) { + log.debug("failed to Update Service Distribution State"); + response = buildErrorResponse(actionResponse.right().value()); + return response; + } + Service service = actionResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(service); + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Service Distribution State"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Service Distribution State"); + log.debug("updateServiceDistributionState failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @POST + @Path("/services/{serviceId}/distribution/{env}/activate") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Activate distribution", httpMethod = "POST", notes = "activate distribution") + @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 409, message = "Service cannot be distributed due to missing deployment artifacts"), @ApiResponse(code = 404, message = "Requested service was not found"), + @ApiResponse(code = 500, message = "Internal Server Error. Please try again later.") }) + public Response activateDistribution(@PathParam("serviceId") final String serviceId, @PathParam("env") final String env, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + Either<Service, ResponseFormat> distResponse = businessLogic.activateDistribution(serviceId, env, modifier, request); + + if (distResponse.isRight()) { + log.debug("failed to activate service distribution"); + response = buildErrorResponse(distResponse.right().value()); + return response; + } + Service service = distResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(service); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Activate Distribution"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Activate Distribution"); + log.debug("activate distribution failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @POST + @Path("/services/{serviceId}/distribution/{did}/markDeployed") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Mark distribution as deployed", httpMethod = "POST", notes = "relevant audit record will be created") + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service was marked as deployed"), @ApiResponse(code = 409, message = "Restricted operation"), @ApiResponse(code = 403, message = "Service is not available"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), @ApiResponse(code = 404, message = "Requested service was not found"), @ApiResponse(code = 500, message = "Internal Server Error. Please try again later.") }) + public Response markDistributionAsDeployed(@PathParam("serviceId") final String serviceId, @PathParam("did") final String did, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + Either<Service, ResponseFormat> distResponse = businessLogic.markDistributionAsDeployed(serviceId, did, modifier); + + if (distResponse.isRight()) { + log.debug("failed to mark distribution as deployed"); + response = buildErrorResponse(distResponse.right().value()); + return response; + } + Service service = distResponse.left().value(); + Object result = RepresentationUtils.toRepresentation(service); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Mark Distribution As Deployed"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Mark Distribution As Deployed"); + log.debug("mark distribution as deployed failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @POST + @Path("/services/{serviceId}/tempUrlToBeDeleted") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal Server Error. Please try again later.") }) + public Response tempUrlToBeDeleted(@PathParam("serviceId") final String serviceId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Response response = null; + try { + ServiceBusinessLogic businessLogic = getServiceBL(context); + Service service = (businessLogic.getService(serviceId, modifier)).left().value(); + Either<Service, ResponseFormat> res = (businessLogic.updateDistributionStatusForActivation(service, modifier, DistributionStatusEnum.DISTRIBUTED)); + + if (res.isRight()) { + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), null); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "tempUrlToBeDeleted"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("tempUrlToBeDeleted"); + log.debug("failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + @GET + @Path("/services/toscatoheat/{artifactName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download service artifact", httpMethod = "GET", notes = "Returns downloaded artifact", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact downloaded"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Artifact not found") }) + public Response downloadServiceArtifact(@PathParam("artifactName") final String artifactName, @Context final HttpServletRequest request) { + Response response = null; + String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER); + String requestURI = request.getRequestURI(); + + try { + log.debug("artifact name = {}", artifactName); + ServletContext context = request.getSession().getServletContext(); + + Either<byte[], ResponseFormat> executeCommand = executeCommand(artifactName); + + if (executeCommand.isRight()) { + log.debug("Failed to convert tosca {} to heat", artifactName); + ResponseFormat responseFormat = executeCommand.right().value(); + response = buildErrorResponse(responseFormat); + } else { + log.debug("Succeed to convert tosca {} to heat", artifactName); + byte[] value = executeCommand.left().value(); + InputStream is = new ByteArrayInputStream(value); + + Map<String, String> headers = new HashMap<>(); + String heatFileName = null; + if (artifactName.indexOf(".") > -1) { + heatFileName = artifactName.substring(0, artifactName.indexOf(".")) + ".heat"; + } else { + heatFileName = artifactName + ".heat"; + } + headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(heatFileName)); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + response = buildOkResponse(responseFormat, is, headers); + } + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "download heat artifact"); + log.error("download artifact failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Either<byte[], ResponseFormat> executeCommand(String artifactName) { + + Configuration configuration = ConfigurationManager.getConfigurationManager().getConfiguration(); + String toscaFilesDir = configuration.getToscaFilesDir(); + if (toscaFilesDir == null) { + toscaFilesDir = "/apps/jetty/base/be/config/tosca"; + } + String heatTranslator = configuration.getHeatTranslatorPath(); + if (heatTranslator == null) { + heatTranslator = "/home/m98835/heat-translator-0.3.0/heat_translator.py"; + } + + log.debug("toscaFilesDir={}", toscaFilesDir); + log.debug("heatTranslator={}", heatTranslator); + + StringBuffer output = new StringBuffer(); + + String heatHeader = configuration.getHeatEnvArtifactHeader(); + String heatFooter = configuration.getHeatEnvArtifactFooter(); + + output.append(heatHeader + "\n"); + + MessageFormat mf = new MessageFormat("python {0} --template-file={1}/{2} --template-type=tosca"); + + log.debug("After creating message format"); + + Object[] objArray = { heatTranslator, toscaFilesDir, artifactName }; + String command = null; + try { + command = mf.format(objArray); + } catch (Exception e) { + log.debug("Failed to convert message format", e); + } + + log.debug("Going to run command {}", command); + + Process p; + try { + p = Runtime.getRuntime().exec(command); + int waitFor = p.waitFor(); + log.debug("waitFor = {}", waitFor); + + if (waitFor != 0) { + log.error("Failed running the command {}", command); + return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.ARTIFACT_NOT_FOUND, artifactName)); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + + String line = ""; + while ((line = reader.readLine()) != null) { + output.append(line + "\n"); + } + + } catch (Exception e) { + log.error("Failed running the command {} {}", command, e); + e.printStackTrace(); + return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + output.append(heatFooter); + + return Either.left(output.toString().getBytes()); + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ToscaDaoServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ToscaDaoServlet.java new file mode 100644 index 0000000000..eea2bfdc42 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ToscaDaoServlet.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import javax.servlet.ServletContext; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.impl.DownloadArtifactLogic; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.info.ServletJsonResponse; +import org.openecomp.sdc.be.resources.api.IResourceUploader; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.slf4j.Logger; +import org.springframework.web.context.WebApplicationContext; + +public abstract class ToscaDaoServlet extends BeGenericServlet { + public abstract Logger getLogger(); + + protected IResourceUploader getResourceUploader(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + + if (webApplicationContextWrapper == null) { + getLogger().error("Failed to get web application context from context."); + return null; + } + + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + + return webApplicationContext.getBean(IResourceUploader.class); + + } + + // protected IToscaYamlBuilder getToscaYamlBuilder(ServletContext context){ + // WebAppContextWrapper webApplicationContextWrapper = + // (WebAppContextWrapper) context + // .getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + // + // if (webApplicationContextWrapper == null) { + // getLogger().error("Failed to get web application context from context."); + // return null; + // } + // + // WebApplicationContext webApplicationContext = + // webApplicationContextWrapper + // .getWebAppContext(context); + // + // return webApplicationContext.getBean(IToscaYamlBuilder.class); + // + // } + + protected DownloadArtifactLogic getLogic(ServletContext context) { + DownloadArtifactLogic downloadLogic = (DownloadArtifactLogic) context.getAttribute(Constants.DOWNLOAD_ARTIFACT_LOGIC_ATTR); + + if (downloadLogic == null) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInitializationError, "DownloadArtifactLogic from context"); + BeEcompErrorManager.getInstance().logBeInitializationError("DownloadArtifactLogic from context"); + return null; + } + return downloadLogic; + } + + protected Response buildResponse(int status, String errorMessage) { + + ServletJsonResponse jsonResponse = new ServletJsonResponse(); + jsonResponse.setDescription(errorMessage); + jsonResponse.setSource(Constants.CATALOG_BE); + + Response response = Response.status(status).entity(jsonResponse).build(); + + return response; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java new file mode 100644 index 0000000000..0825a25cbe --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.util.Map; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Types Fetch Servlet", description = "Types Fetch Servlet") +@Singleton +public class TypesFetchServlet extends AbstractValidationsServlet { + + private static Logger log = LoggerFactory.getLogger(TypesFetchServlet.class.getName()); + + @GET + @Path("dataTypes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get data types", httpMethod = "GET", notes = "Returns data types", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "datatypes"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Data types not found") }) + public Response getAllDataTypesServlet(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + Wrapper<Response> responseWrapper = new Wrapper<Response>(); + Wrapper<User> userWrapper = new Wrapper<User>(); + ServletContext context = request.getSession().getServletContext(); + + try { + init(log); + validateUserExist(responseWrapper, userWrapper, userId); + + if (responseWrapper.isEmpty()) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + PropertyBusinessLogic businessLogic = getPropertyBL(context); + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = businessLogic.getAllDataTypes(); + + if (allDataTypes.isRight()) { + log.info("Failed to get all dara types. Reason - ", allDataTypes.right().value()); + Response errorResponse = buildErrorResponse(allDataTypes.right().value()); + responseWrapper.setInnerElement(errorResponse); + + // return buildErrorResponse(allDataTypes.right().value()); + } else { + Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); + Response okResponse = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), dataTypes); + responseWrapper.setInnerElement(okResponse); + } + } + + return responseWrapper.getInnerElement(); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get all data types"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property"); + log.debug("get all data types failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + + private PropertyBusinessLogic getPropertyBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + PropertyBusinessLogic propertytBl = webApplicationContext.getBean(PropertyBusinessLogic.class); + return propertytBl; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java new file mode 100644 index 0000000000..6ba8c521f1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java @@ -0,0 +1,317 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import javax.annotation.Resource; +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.openecomp.sdc.be.components.impl.CapabilityTypeImportManager; +import org.openecomp.sdc.be.components.impl.CategoriesImportManager; +import org.openecomp.sdc.be.components.impl.DataTypeImportManager; +import org.openecomp.sdc.be.components.impl.GroupTypeImportManager; +import org.openecomp.sdc.be.components.impl.InterfaceLifecycleTypeImportManager; +import org.openecomp.sdc.be.components.impl.PolicyTypeImportManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GroupTypeDefinition; +import org.openecomp.sdc.be.model.PolicyTypeDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerTwoParam; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.WebApplicationContext; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog/uploadType") +@Api(value = "Catalog Types Upload", description = "Upload Type from yaml") +@Singleton +public class TypesUploadServlet extends AbstractValidationsServlet { + @Resource + private CapabilityTypeImportManager capabilityTypeImportManager; + + @Resource + private InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager; + + @Resource + private CategoriesImportManager categoriesImportManager; + + @Resource + private DataTypeImportManager dataTypeImportManager; + + @Resource + private GroupTypeImportManager groupTypeImportManager; + + @Resource + private PolicyTypeImportManager policyTypeImportManager; + + private static Logger log = LoggerFactory.getLogger(TypesUploadServlet.class.getName()); + + @POST + @Path("/capability") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Capability Type from yaml", httpMethod = "POST", notes = "Returns created Capability Type", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Capability Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Capability Type already exist") }) + public Response uploadCapabilityType(@ApiParam("FileInputStream") @FormDataParam("capabilityTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) { + + capabilityTypeImportManager = initElementTypeImportManager(request.getSession().getServletContext(), () -> CapabilityTypeImportManager.class); + ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload)); + return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name()); + + } + + @POST + @Path("/interfaceLifecycle") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Interface Lyfecycle Type from yaml", httpMethod = "POST", notes = "Returns created Interface Lifecycle Type", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Interface Lifecycle Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Interface Lifecycle Type already exist") }) + public Response uploadInterfaceLifecycleType(@ApiParam("FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) { + + interfaceLifecycleTypeImportManager = initElementTypeImportManager(request.getSession().getServletContext(), () -> InterfaceLifecycleTypeImportManager.class); + ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload)); + return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types"); + } + + @POST + @Path("/categories") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created categories", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Categories created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Category already exist") }) + public Response uploadCategories(@ApiParam("FileInputStream") @FormDataParam("categoriesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) { + + categoriesImportManager = initElementTypeImportManager(request.getSession().getServletContext(), () -> CategoriesImportManager.class); + ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload)); + return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories"); + + } + + @POST + @Path("/datatypes") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created data types", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Data types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Data types already exist") }) + public Response uploadDataTypes(@ApiParam("FileInputStream") @FormDataParam("dataTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) { + + dataTypeImportManager = initElementTypeImportManager(request.getSession().getServletContext(), () -> DataTypeImportManager.class); + ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createDataTypes(responseWrapper, ymlPayload); + return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.DataType.getName()); + + } + + @POST + @Path("/grouptypes") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create GroupTypes from yaml", httpMethod = "POST", notes = "Returns created group types", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "group types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "group types already exist") }) + public Response uploadGroupTypes(@ApiParam("FileInputStream") @FormDataParam("groupTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) { + + groupTypeImportManager = initElementTypeImportManager(request.getSession().getServletContext(), () -> GroupTypeImportManager.class); + ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createGroupTypes(responseWrapper, ymlPayload); + + return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.GroupType.getName()); + } + + @POST + @Path("/policytypes") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create PolicyTypes from yaml", httpMethod = "POST", notes = "Returns created policy types", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "policy types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "policy types already exist") }) + public Response uploadPolicyTypes(@ApiParam("FileInputStream") @FormDataParam("policyTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) { + + policyTypeImportManager = initElementTypeImportManager(request.getSession().getServletContext(), () -> PolicyTypeImportManager.class); + ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createPolicyTypes(responseWrapper, ymlPayload); + + return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.PolicyType.getName()); + + } + + private Response uploadElementTypeServletLogic(ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod, File file, final HttpServletRequest request, String creator, String elementTypeName) { + init(log); + String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER); + try { + Wrapper<Response> responseWrapper = new Wrapper<>(); + Wrapper<User> userWrapper = new Wrapper<>(); + Wrapper<String> yamlStringWrapper = new Wrapper<>(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + validateUserExist(responseWrapper, userWrapper, userId); + + if (responseWrapper.isEmpty()) { + validateUserRole(responseWrapper, userWrapper.getInnerElement()); + } + + if (responseWrapper.isEmpty()) { + validateDataNotNull(responseWrapper, file); + } + + if (responseWrapper.isEmpty()) { + fillZipContents(yamlStringWrapper, file); + } + + if (responseWrapper.isEmpty()) { + createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement()); + } + + return responseWrapper.getInnerElement(); + + } catch (Exception e) { + log.debug("create {} failed with exception: {}", elementTypeName, e); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create " + elementTypeName); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private <T> void createElementsType(Wrapper<Response> responseWrapper, Supplier<Either<T, ResponseFormat>> elementsCreater) { + Either<T, ResponseFormat> eitherResult = elementsCreater.get(); + if (eitherResult.isRight()) { + Response response = buildErrorResponse(eitherResult.right().value()); + responseWrapper.setInnerElement(response); + } else { + Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), eitherResult.left().value()); + responseWrapper.setInnerElement(response); + } + } + + // data types + private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml) { + final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> dataTypeImportManager.createDataTypes(dataTypesYml); + buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.DATA_TYPE_ALREADY_EXIST, NodeTypeEnum.DataType.name()); + } + + // group types + private void createGroupTypes(Wrapper<Response> responseWrapper, String groupTypesYml) { + final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> groupTypeImportManager.createGroupTypes(groupTypesYml); + buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.GROUP_TYPE_ALREADY_EXIST, NodeTypeEnum.GroupType.name()); + + } + + // policy types + private void createPolicyTypes(Wrapper<Response> responseWrapper, String policyTypesYml) { + final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> policyTypeImportManager.createPolicyTypes(policyTypesYml); + buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.POLICY_TYPE_ALREADY_EXIST, NodeTypeEnum.PolicyType.name()); + + } + + // data types + private <ElementTypeDefinition> void buildStatusForElementTypeCreate(Wrapper<Response> responseWrapper, Supplier<Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml, + ActionStatus alreadyExistStatus, String elementTypeName) { + + Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> eitherResult = generateElementTypeFromYml.get(); + + if (eitherResult.isRight()) { + Response response = buildErrorResponse(eitherResult.right().value()); + responseWrapper.setInnerElement(response); + } else { + Object representation; + try { + List<ImmutablePair<ElementTypeDefinition, Boolean>> list = eitherResult.left().value(); + ActionStatus status = ActionStatus.OK; + if (list != null) { + + // Group result by the right value - true or false. + // I.e., get the number of data types which are new and + // which are old. + Map<Boolean, List<ImmutablePair<ElementTypeDefinition, Boolean>>> collect = list.stream().collect(Collectors.groupingBy(ImmutablePair<ElementTypeDefinition, Boolean>::getRight)); + if (collect != null) { + Set<Boolean> keySet = collect.keySet(); + if (keySet.size() == 1) { + Boolean isNew = keySet.iterator().next(); + if (isNew.booleanValue() == true) { + // all data types created at the first time + status = ActionStatus.CREATED; + } else { + // All data types already exists + + status = alreadyExistStatus; + } + } + } + } + representation = RepresentationUtils.toRepresentation(eitherResult.left().value()); + + Response response = buildOkResponse(getComponentsUtils().getResponseFormat(status), representation); + responseWrapper.setInnerElement(response); + + } catch (IOException e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create " + elementTypeName); + log.debug("failed to convert {} to json", elementTypeName, e); + Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + responseWrapper.setInnerElement(response); + } + } + } + + private <T> T initElementTypeImportManager(ServletContext context, Supplier<Class<T>> classGetter) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + T elementTypeImortManager = webApplicationContext.getBean(classGetter.get()); + return elementTypeImortManager; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java new file mode 100644 index 0000000000..c700c31a64 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java @@ -0,0 +1,516 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.servlets; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.FunctionalMenuInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcabi.aspects.Loggable; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; +import com.wordnik.swagger.annotations.ApiResponse; +import com.wordnik.swagger.annotations.ApiResponses; + +import fj.data.Either; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/user") +@Api(value = "User Administration", description = "User admininstarator operations") +@Singleton +public class UserAdminServlet extends BeGenericServlet { + + private static final String ROLE_DELIMITER = ","; + private static Logger log = LoggerFactory.getLogger(UserAdminServlet.class.getName()); + + /*************************************** + * API start + *************************************************************/ + + /* User by userId CRUD start */ + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve all user details + @GET + @Path("/{userId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "retrieve user details", httpMethod = "GET", notes = "Returns user details according to userId", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns user Ok"), @ApiResponse(code = 404, message = "User not found"), @ApiResponse(code = 405, message = "Method Not Allowed"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response get(@ApiParam(value = "userId of user to get", required = true) @PathParam("userId") final String userId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + + UserBusinessLogic userAdminManager = getUserAdminManager(request.getSession().getServletContext()); + + try { + Either<User, ActionStatus> either = userAdminManager.getUser(userId, false); + + if (either.isRight()) { + return buildErrorResponse(getComponentsUtils().getResponseFormatByUserId(either.right().value(), userId)); + } else { + if (either.left().value() != null) { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), either.left().value()); + } else { + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get User"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get User"); + log.debug("get user failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // update user - internal API + /* + * @POST + * + * @Path("/{userId}") + * + * @Consumes(MediaType.APPLICATION_JSON) + * + * @Produces(MediaType.APPLICATION_JSON) + * + * @ApiOperation(value = "update user - internal API", notes = "Update user", response = User.class) + * + * @ApiResponses(value = { + * + * @ApiResponse(code = 200, message = "Update user OK"), + * + * @ApiResponse(code = 400, message = "Invalid Content."), + * + * @ApiResponse(code = 403, message = "Missing information/Restricted operation"), + * + * @ApiResponse(code = 404, message = "User not found"), + * + * @ApiResponse(code = 405, message = "Method Not Allowed"), + * + * @ApiResponse(code = 409, message = "User already exists"), + * + * @ApiResponse(code = 500, message = "Internal Server Error") }) public Response updateUser(@ApiParam(value="userId of user to get", required=true) @PathParam("userId") final String UserIdUpdateUser, + * + * @Context final HttpServletRequest request, + * + * @ApiParam(value="json describe the update user", required=true) String data, + * + * @HeaderParam(value = Constants.USER_ID_HEADER) String modifierAttId) { + * + * ServletContext context = request.getSession().getServletContext(); + * + * String url = request.getMethod() + " " + request.getRequestURI(); log.debug("Start handle request of {}", url); + * + * // get modifier id User modifier = new User(); modifier.setUserId(modifierAttId); log.debug("modifier id is {}", modifierAttId); + * + * Response response = null; + * + * try { UserAdminBuisinessLogic businessLogic = getUserAdminManager(context); User updateInfoUser = getComponentsUtils().convertJsonToObject(data, modifier, User.class, AuditingActionEnum.UPDATE_USER).left().value(); Either<User, ResponseFormat> + * updateUserResponse = null;// businessLogic.updateUser(modifier, UserIdUpdateUser, updateInfoUser); + * + * if (updateUserResponse.isRight()) { log.debug("failed to update user metadata"); response = buildErrorResponse(updateUserResponse.right().value()); return response; } response = + * buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), updateUserResponse.left().value()); return response; + * + * } catch (Exception e) { BeEcompErrorManager.getInstance().processEcompError(EcompErrorName. BeRestApiGeneralError, "Update User Metadata"); log.debug("Update User Metadata failed with exception", e); response = + * buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus. GENERAL_ERROR)); return response; + * + * } } + * + */ + /* User userId CRUD end */ + + /* User role CRUD start */ + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // retrieve user role + @GET + @Path("/{userId}/role") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "retrieve user role", notes = "Returns user role according to userId", response = String.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns user role Ok"), @ApiResponse(code = 404, message = "User not found"), @ApiResponse(code = 405, message = "Method Not Allowed"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getRole(@ApiParam(value = "userId of user to get", required = true) @PathParam("userId") final String userId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getRole) Start handle request of {}", url); + + UserBusinessLogic userAdminManager = getUserAdminManager(request.getSession().getServletContext()); + + try { + Either<User, ActionStatus> either = userAdminManager.getUser(userId, false); + if (either.isRight()) { + return buildErrorResponse(getComponentsUtils().getResponseFormatByUserId(either.right().value(), userId)); + } else { + if (either.left().value() != null) { + String roleJson = ("{ \"role\" : \"" + either.left().value().getRole().toString() + "\" }"); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), roleJson); + } else { + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get User Role"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get User Role"); + log.debug("Get user role failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // update user role + @POST + @Path("/{userId}/role") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "update user role", notes = "Update user role", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Update user OK"), @ApiResponse(code = 400, message = "Invalid Content."), @ApiResponse(code = 403, message = "Missing information/Restricted operation"), + @ApiResponse(code = 404, message = "User not found"), @ApiResponse(code = 405, message = "Method Not Allowed"), @ApiResponse(code = 409, message = "User already exists"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response updateUserRole(@ApiParam(value = "userId of user to get", required = true) @PathParam("userId") final String UserIdUpdateUser, @Context final HttpServletRequest request, + @ApiParam(value = "json describe the update role", required = true) String data, @HeaderParam(value = Constants.USER_ID_HEADER) String modifierUserId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(modifierUserId); + log.debug("modifier id is {}", modifierUserId); + + Response response = null; + + try { + UserBusinessLogic businessLogic = getUserAdminManager(context); + User updateInfoUser = getComponentsUtils().convertJsonToObject(data, modifier, User.class, AuditingActionEnum.UPDATE_USER).left().value(); + Either<User, ResponseFormat> updateUserResponse = businessLogic.updateUserRole(modifier, UserIdUpdateUser, updateInfoUser.getRole()); + + if (updateUserResponse.isRight()) { + log.debug("failed to update user role"); + response = buildErrorResponse(updateUserResponse.right().value()); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), updateUserResponse.left().value()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update User Metadata"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update User Metadata"); + log.debug("Update User Role failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + /* User role CRUD end */ + + /* New user CRUD start */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "add user", httpMethod = "POST", notes = "Provision new user", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "New user created"), @ApiResponse(code = 400, message = "Invalid Content."), @ApiResponse(code = 403, message = "Missing information"), + @ApiResponse(code = 405, message = "Method Not Allowed"), @ApiResponse(code = 409, message = "User already exists"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response createUser(@Context final HttpServletRequest request, @ApiParam(value = "json describe the user", required = true) String newUserData, @HeaderParam(value = Constants.USER_ID_HEADER) String modifierAttId) { + + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(modifierAttId); + log.debug("modifier id is {}", modifierAttId); + + Response response = null; + + try { + UserBusinessLogic businessLogic = getUserAdminManager(context); + User newUserInfo = getComponentsUtils().convertJsonToObject(newUserData, modifier, User.class, AuditingActionEnum.ADD_USER).left().value(); + Either<User, ResponseFormat> createUserResponse = businessLogic.createUser(modifier, newUserInfo); + + if (createUserResponse.isRight()) { + log.debug("failed to create user"); + response = buildErrorResponse(createUserResponse.right().value()); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), createUserResponse.left().value()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update User Metadata"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update User Metadata"); + log.debug("Create User failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + + } + } + + /* New user CRUD end */ + + /* User authorization start */ + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // User Authorization + @GET + @Path("/authorize") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + + @ApiOperation(value = "authorize", notes = "authorize user", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns user Ok"), @ApiResponse(code = 403, message = "Restricted Access"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response authorize(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @HeaderParam("HTTP_CSP_FIRSTNAME") String firstName, @HeaderParam("HTTP_CSP_LASTNAME") String lastName, + @HeaderParam("HTTP_CSP_EMAIL") String email) { + + try { + userId = (userId != null ? URLDecoder.decode(userId, "UTF-8") : null); + firstName = (firstName != null ? URLDecoder.decode(firstName, "UTF-8") : null); + lastName = (lastName != null ? URLDecoder.decode(lastName, "UTF-8") : null); + email = (email != null ? URLDecoder.decode(email, "UTF-8") : null); + } catch (UnsupportedEncodingException e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Authorize User - decode headers"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Authorize User - decode headers"); + ResponseFormat errorResponseWrapper = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(errorResponseWrapper); + } + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User authUser = new User(); + authUser.setUserId(userId); + authUser.setFirstName(firstName); + authUser.setLastName(lastName); + authUser.setEmail(email); + log.debug("auth user id is {}", userId); + + Response response = null; + try { + UserBusinessLogic userAdminManager = getUserAdminManager(context); + Either<User, ResponseFormat> authorize = userAdminManager.authorize(authUser); + + if (authorize.isRight()) { + log.debug("authorize user failed"); + response = buildErrorResponse(authorize.right().value()); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), authorize.left().value()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get ASDC users"); + log.debug("authorize user failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + /* User authorization end */ + + @GET + @Path("/admins") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "retrieve all administrators", httpMethod = "GET", notes = "Returns all administrators", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns user Ok"), @ApiResponse(code = 405, message = "Method Not Allowed"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getAdminsUser(@PathParam("userId") final String userId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + + UserBusinessLogic userAdminManager = getUserAdminManager(request.getSession().getServletContext()); + + try { + Either<List<User>, ResponseFormat> either = userAdminManager.getAllAdminUsers(request.getSession().getServletContext()); + + if (either.isRight()) { + log.debug("Failed to get all admin users"); + return buildErrorResponse(either.right().value()); + } else { + if (either.left().value() != null) { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), either.left().value()); + } else { + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get All Administrators"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get All Administrators"); + log.debug("get all admins failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/users") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Retrieve the list of all active ASDC users or only group of users having specific roles.", httpMethod = "GET", notes = "Returns list of users with the specified roles, or all of users in the case of empty 'roles' header", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns users Ok"), @ApiResponse(code = 204, message = "No provisioned ASDC users of requested role"), @ApiResponse(code = 403, message = "Restricted Access"), + @ApiResponse(code = 400, message = "Missing content"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getUsersList(@Context final HttpServletRequest request, @ApiParam(value = "Any active user's USER_ID") @HeaderParam(Constants.USER_ID_HEADER) final String userId, + @ApiParam(value = "TESTER,DESIGNER,PRODUCT_STRATEGIST,OPS,PRODUCT_MANAGER,GOVERNOR, ADMIN OR all users by not typing anything") @QueryParam("roles") final String roles) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + log.debug("modifier id is {}", userId); + + List<String> rolesList = new ArrayList<>(); + if (roles != null && !roles.trim().isEmpty()) { + String[] rolesArr = roles.split(ROLE_DELIMITER); + for (String role : rolesArr) { + rolesList.add(role.trim()); + } + } + + try { + UserBusinessLogic userAdminManager = getUserAdminManager(context); + Either<List<User>, ResponseFormat> either = userAdminManager.getUsersList(userId, rolesList, roles); + + if (either.isRight()) { + log.debug("Failed to get ASDC users"); + return buildErrorResponse(either.right().value()); + } else { + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), either.left().value()); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get ASDC users"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get ASDC users"); + log.debug("get users failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // delete user + @DELETE + @Path("/{userId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "delete user", notes = "Delete user", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Update deleted OK"), @ApiResponse(code = 400, message = "Invalid Content."), @ApiResponse(code = 403, message = "Missing information"), + @ApiResponse(code = 404, message = "User not found"), @ApiResponse(code = 405, message = "Method Not Allowed"), @ApiResponse(code = 409, message = "Restricted operation"), @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response deActivateUser(@ApiParam(value = "userId of user to get", required = true) @PathParam("userId") final String userId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userIdHeader) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + User modifier = new User(); + modifier.setUserId(userIdHeader); + log.debug("modifier id is {}", userIdHeader); + + Response response = null; + try { + UserBusinessLogic userAdminManager = getUserAdminManager(context); + Either<User, ResponseFormat> deactiveUserResponse = userAdminManager.deActivateUser(modifier, userId); + + if (deactiveUserResponse.isRight()) { + log.debug("Failed to deactivate user"); + response = buildErrorResponse(deactiveUserResponse.right().value()); + return response; + } + response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), deactiveUserResponse.left().value()); + return response; + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get ASDC users"); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get ASDC users"); + log.debug("deactivate user failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @GET + @Path("/{userId}/functionalmenu") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "retrieve user details", httpMethod = "GET", notes = "Returns user details according to userId", response = User.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns user Ok"), @ApiResponse(code = 404, message = "User not found"), @ApiResponse(code = 405, message = "Method Not Allowed"), + @ApiResponse(code = 500, message = "Internal Server Error") }) + public Response getFunctionalMenu(@ApiParam(value = "userId of user to get", required = true) @PathParam("userId") final String userId, @Context final HttpServletRequest request) { + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + + UserBusinessLogic userAdminManager = getUserAdminManager(request.getSession().getServletContext()); + + try { + Either<FunctionalMenuInfo, ActionStatus> functionalMenuResp = userAdminManager.getFunctionalMenu(userId); + + if (functionalMenuResp.isRight()) { + return buildErrorResponse(getComponentsUtils().getResponseFormatByUserId(functionalMenuResp.right().value(), userId)); + } else { + FunctionalMenuInfo functionalMenuInfo = functionalMenuResp.left().value(); + if (functionalMenuInfo != null && functionalMenuInfo.getFunctionalMenu() != null) { + log.debug("Functional menu fetched is {}", functionalMenuInfo.getFunctionalMenu()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), functionalMenuInfo.getFunctionalMenu()); + } else { + log.debug("Functional menu is null"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get User"); + log.debug("get user failed with unexpected error: {}", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/switchover/detector/SwitchoverDetector.java b/catalog-be/src/main/java/org/openecomp/sdc/be/switchover/detector/SwitchoverDetector.java new file mode 100644 index 0000000000..4027144911 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/switchover/detector/SwitchoverDetector.java @@ -0,0 +1,315 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.switchover.detector; + +import java.net.InetAddress; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.apache.commons.codec.binary.Base64; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.Configuration.SwitchoverDetectorConfig; +import org.openecomp.sdc.be.dao.rest.HttpRestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component("switchover-detector") +public class SwitchoverDetector { + + protected static String SWITCHOVER_DETECTOR_LOG_CONTEXT = "switchover.detector"; + + private static Logger switchoverLogger = LoggerFactory.getLogger(SWITCHOVER_DETECTOR_LOG_CONTEXT); + + private SwitchoverDetectorConfig switchoverDetectorConfig; + + private Properties authHeader = null; + + private long detectorInterval = 60; + + private int maxBeQueryAttempts = 3; + + private int maxFeQueryAttempts = 3; + + private Boolean beMatch = null; + + private Boolean feMatch = null; + + private static Logger logger = LoggerFactory.getLogger(SwitchoverDetector.class.getName()); + + private volatile String siteMode = SwitchoverDetectorState.UNKNOWN.getState(); + + private ScheduledFuture<?> scheduledFuture = null; + + ScheduledExecutorService switchoverDetectorScheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "Switchover-Detector-Task"); + } + }); + + SwitchoverDetectorScheduledTask switchoverDetectorScheduledTask = null; + + public enum SwitchoverDetectorState { + + UNKNOWN("unknown"), ACTIVE("active"), STANDBY("standby"); + + private String state; + + SwitchoverDetectorState(String state) { + this.state = state; + } + + public String getState() { + return state; + } + } + + public enum SwitchoverDetectorGroup { + + BE_SET("beSet"), FE_SET("feSet"); + + private String group; + + SwitchoverDetectorGroup(String group) { + this.group = group; + } + + public String getGroup() { + return group; + } + } + + public String getSiteMode() { + return siteMode; + } + + public void setSiteMode(String mode) { + this.siteMode = mode; + } + + private Boolean queryBe() { + return queryGss(switchoverDetectorConfig.getgBeFqdn(), switchoverDetectorConfig.getBeVip(), maxBeQueryAttempts); + } + + private Boolean queryFe() { + return queryGss(switchoverDetectorConfig.getgFeFqdn(), switchoverDetectorConfig.getFeVip(), maxFeQueryAttempts); + } + + private void setAuthorizationProperties() { + String userInfo = switchoverDetectorConfig.getChangePriorityUser() + ":" + switchoverDetectorConfig.getChangePriorityPassword(); + String auth = "Basic " + new String(new Base64().encode(userInfo.getBytes())); + authHeader = new Properties(); + authHeader.put("Authorization", auth); + } + + private void initializeSiteMode() { + while (siteMode == SwitchoverDetectorState.UNKNOWN.getState()) { + + beMatch = queryBe(); + feMatch = queryFe(); + + if (beMatch == feMatch && beMatch != null) { + if (beMatch) { + setSiteMode(SwitchoverDetectorState.ACTIVE.getState()); + } else { + setSiteMode(SwitchoverDetectorState.STANDBY.getState()); + } + } + } + } + + private Boolean queryGss(String fqdn, String vip, int maxAttempts) { + + Boolean result = null; + int attempts = 0; + + while (result == null && (++attempts < maxAttempts)) { + try { + InetAddress inetAddress = InetAddress.getByName(fqdn); + result = inetAddress.getHostAddress().equals(vip); + + } catch (Exception e) { + String message = e.getMessage(); + if (message == null) { + message = e.getClass().getName(); + } + switchoverLogger.debug("Error occured during switchover detector query, Result is {}", message); + } + } + if (null == result) { + BeEcompErrorManager.getInstance().logFqdnResolveError(SWITCHOVER_DETECTOR_LOG_CONTEXT, "host " + fqdn + " not resolved after " + attempts + " attempts"); + } + return result; + } + + public class SwitchoverDetectorScheduledTask implements Runnable { + + public SwitchoverDetectorScheduledTask() { + + } + + @Override + public void run() { + switchoverLogger.trace("Executing Switchover Detector Task - Start"); + + initializeSiteMode(); + + Boolean beRes = queryBe(); + Boolean feRes = queryFe(); + + Boolean updateRequired = siteMode == SwitchoverDetectorState.STANDBY.getState() && (beRes || feRes); + + updateSiteModeAndPriority(beRes && feRes, siteMode == SwitchoverDetectorState.STANDBY.getState(), updateRequired); + + beMatch = beRes; + feMatch = feRes; + } + + ExecutorService switchoverDetectorExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "Switchover-Detector-Thread"); + } + }); + + private void updateSiteModeAndPriority(Boolean bothMatch, Boolean previousModeStandby, Boolean updateRequired) { + if (bothMatch && previousModeStandby) { + logger.trace("Site switch over was done. Site is now in active mode"); + setSiteMode(SwitchoverDetectorState.ACTIVE.getState()); + BeEcompErrorManager.getInstance().logSiteSwitchoverInfo(SWITCHOVER_DETECTOR_LOG_CONTEXT, siteMode); + } else if (!bothMatch && !previousModeStandby) { + logger.trace("Site switch over was done. Site is now in stand-by mode"); + setSiteMode(SwitchoverDetectorState.STANDBY.getState()); + BeEcompErrorManager.getInstance().logSiteSwitchoverInfo(SWITCHOVER_DETECTOR_LOG_CONTEXT, siteMode); + } + if (updateRequired) { + changeSitePriority(SwitchoverDetectorGroup.BE_SET.getGroup()); + changeSitePriority(SwitchoverDetectorGroup.FE_SET.getGroup()); + publishNetwork(); + } + } + + private void changeSitePriority(String groupToSet) { + + String url = switchoverDetectorConfig.getGroups().get(groupToSet).getChangePriorityUrl(); + String body = switchoverDetectorConfig.getGroups().get(groupToSet).getChangePriorityBody(); + + HttpRestClient httpRestClient = new HttpRestClient(); + + try { + httpRestClient.doPUT(url, authHeader, body); + + } catch (Exception e) { + String message = e.getMessage(); + if (message == null) { + message = e.getClass().getName(); + } + switchoverLogger.error("Error occured during change site priority request, Result is {}", message); + } + + } + + private void publishNetwork() { + + String url = switchoverDetectorConfig.getPublishNetworkUrl(); + String body = switchoverDetectorConfig.getPublishNetworkBody(); + + HttpRestClient httpRestClient = new HttpRestClient(); + + try { + httpRestClient.doPOST(url, authHeader, body); + + } catch (Exception e) { + String message = e.getMessage(); + if (message == null) { + message = e.getClass().getName(); + } + switchoverLogger.error("Error occured during publish network request, Result is {}", message); + } + } + + } + + @PostConstruct + private void init() { + logger.info("Enter init method of SwitchoverDetector"); + + switchoverDetectorConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getSwitchoverDetector(); + + if (!switchoverDetectorConfig.getEnabled()) { + logger.info("switchover detector service is disabled"); + return; + } + + Long detectorIntervalConfig = switchoverDetectorConfig.getInterval(); + if (detectorIntervalConfig != null) { + detectorInterval = detectorIntervalConfig.longValue(); + } + + Integer maxAttempts = switchoverDetectorConfig.getBeResolveAttempts(); + if (maxAttempts != null) { + maxBeQueryAttempts = maxAttempts.intValue(); + } + maxAttempts = switchoverDetectorConfig.getFeResolveAttempts(); + if (maxAttempts != null) { + maxFeQueryAttempts = maxAttempts.intValue(); + } + + setAuthorizationProperties(); + logger.info("switchover detector service is enabled, interval is {} seconds", detectorInterval); + + this.switchoverDetectorScheduledTask = new SwitchoverDetectorScheduledTask(); + startSwitchoverDetectorTask(); + logger.trace("Exit init method of SwitchoverDetector"); + + } + + @PreDestroy + private void destroy() { + + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + scheduledFuture = null; + } + + if (switchoverDetectorScheduler != null) { + switchoverDetectorScheduler.shutdown(); + } + + } + + public void startSwitchoverDetectorTask() { + if (this.scheduledFuture == null) { + this.scheduledFuture = this.switchoverDetectorScheduler.scheduleAtFixedRate(switchoverDetectorScheduledTask, 0, detectorInterval, TimeUnit.SECONDS); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ArtifactTypes.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ArtifactTypes.java new file mode 100644 index 0000000000..85b4493c8e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ArtifactTypes.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.util.List; + +import org.openecomp.sdc.generator.data.ArtifactType; + +public class ArtifactTypes { + private List<ArtifactType> artifactTypes; + + public List<ArtifactType> getArtifactTypes() { + return artifactTypes; + } + + public void setArtifactTypes(List<ArtifactType> artifactTypes) { + this.artifactTypes = artifactTypes; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CSARTool.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CSARTool.java new file mode 100644 index 0000000000..7fecced358 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CSARTool.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import org.openecomp.sdc.be.model.Component; + +public class CSARTool { + public static byte[] createCsar(Component component) { + + final String TOSCA_META_VERSION = "1.0"; + final String CSAR_VERSION = component.getCsarVersion(); + final String CREATED_BY = component.getCreatorFullName(); + final String ENTRY_DEFINITIONS = component.getNormalizedName(); + + /* + * StringBuilder builder = new StringBuilder(); try( FileOutputStream f = new FileOutputStream("test.zip"); ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(f)); ){ } + */ + + return null; + } + + public static String createToscaBlock0(String metaFileVersion, String csarVersion, String createdBy, String entryDef) { + final String BLOCK_0_TEMPLATE = "TOSCA-Meta-File-Version: %s"; + + return null; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabiltyRequirementConvertor.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabiltyRequirementConvertor.java new file mode 100644 index 0000000000..d1f2557413 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabiltyRequirementConvertor.java @@ -0,0 +1,261 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.resources.data.CapabilityData; +import org.openecomp.sdc.be.resources.data.RequirementData; +import org.openecomp.sdc.be.tosca.model.SubstitutionMapping; +import org.openecomp.sdc.be.tosca.model.ToscaCapability; +import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate; +import org.openecomp.sdc.be.tosca.model.ToscaNodeType; +import org.openecomp.sdc.be.tosca.model.ToscaProperty; +import org.openecomp.sdc.be.tosca.model.ToscaRequirement; +import org.openecomp.sdc.be.tosca.model.ToscaTemplateCapability; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class CapabiltyRequirementConvertor { + private static CapabiltyRequirementConvertor instance; + + protected CapabiltyRequirementConvertor() { + + } + + public static synchronized CapabiltyRequirementConvertor getInstance() { + if (instance == null) { + instance = new CapabiltyRequirementConvertor(); + } + return instance; + } + + private static Logger log = LoggerFactory.getLogger(CapabiltyRequirementConvertor.class.getName()); + + public Either<ToscaNodeTemplate, ToscaError> convertComponentInstanceCapabilties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate) { + + Map<String, List<CapabilityDefinition>> capabilitiesInst = componentInstance.getCapabilities(); + if (capabilitiesInst != null && !capabilitiesInst.isEmpty()) { + Map<String, ToscaTemplateCapability> capabilties = new HashMap<>(); + capabilitiesInst.entrySet().forEach(e -> { + List<CapabilityDefinition> capList = e.getValue(); + if (capList != null && !capList.isEmpty()) { + capList.forEach(c -> { + convertOverridenProperties(componentInstance, dataTypes, capabilties, c); + }); + } + }); + if (capabilties != null && !capabilties.isEmpty()) { + nodeTemplate.setCapabilities(capabilties); + } + } + return Either.left(nodeTemplate); + } + + private void convertOverridenProperties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, Map<String, ToscaTemplateCapability> capabilties, CapabilityDefinition c) { + List<ComponentInstanceProperty> properties = c.getProperties(); + if (properties != null && !properties.isEmpty()) { + properties.stream().filter(p -> (p.getValueUniqueUid() != null)).forEach(p -> { + convertOverridenProperty(componentInstance, dataTypes, capabilties, c, p); + }); + } + } + + private void convertOverridenProperty(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, Map<String, ToscaTemplateCapability> capabilties, CapabilityDefinition c, ComponentInstanceProperty p) { + if (log.isDebugEnabled()) { + log.debug("Exist overriden property {} for capabity {} with value {}", p.getName(), c.getName(), p.getValue()); + } + ToscaTemplateCapability toscaTemplateCapability = capabilties.get(c.getName()); + if (toscaTemplateCapability == null) { + toscaTemplateCapability = new ToscaTemplateCapability(); + capabilties.put(c.getName(), toscaTemplateCapability); + } + Map<String, Object> toscaCapProp = toscaTemplateCapability.getProperties(); + if (toscaCapProp == null) { + toscaCapProp = new HashMap<>(); + } + Object convertedValue = convertInstanceProperty(dataTypes, componentInstance, p); + toscaCapProp.put(p.getName(), convertedValue); + toscaTemplateCapability.setProperties(toscaCapProp); + } + + private Object convertInstanceProperty(Map<String, DataTypeDefinition> dataTypes, ComponentInstance componentInstance, ComponentInstanceProperty prop) { + log.debug("Convert property {} for instance {}", prop.getName(), componentInstance.getUniqueId()); + String propertyType = prop.getType(); + String innerType = null; + if (prop.getSchema() != null && prop.getSchema().getProperty() != null) { + innerType = prop.getSchema().getProperty().getType(); + } + Object convertedValue = PropertyConvertor.getInstance().convertToToscaObject(propertyType, prop.getValue(), innerType, dataTypes); + return convertedValue; + } + + public Either<ToscaNodeType, ToscaError> convertRequirements(Component component, ToscaNodeType nodeType) { + List<Map<String, ToscaRequirement>> toscaRequirements = convertRequirementsAsList(component); + if (!toscaRequirements.isEmpty()) { + nodeType.setRequirements(toscaRequirements); + } + log.debug("Finish convert Requirements for node type"); + + return Either.left(nodeType); + } + + public Either<SubstitutionMapping, ToscaError> convertRequirements(Component component, SubstitutionMapping substitutionMapping) { + Map<String, ToscaRequirement> toscaRequirements = convertRequirementsAsMap(component); + if (!toscaRequirements.isEmpty()) { + substitutionMapping.setRequirements(toscaRequirements); + } + log.debug("Finish convert Requirements for node type"); + + return Either.left(substitutionMapping); + } + + private List<Map<String, ToscaRequirement>> convertRequirementsAsList(Component component) { + Map<String, List<RequirementDefinition>> requirements = component.getRequirements(); + List<Map<String, ToscaRequirement>> toscaRequirements = new ArrayList<>(); + if (requirements != null) { + boolean isNodeType = ToscaUtils.isNodeType(component); + for (Map.Entry<String, List<RequirementDefinition>> entry : requirements.entrySet()) { + entry.getValue().stream().filter(r -> (!isNodeType || (isNodeType && component.getUniqueId().equals(r.getOwnerId())))).forEach(r -> { + ImmutablePair<String, ToscaRequirement> pair = convertRequirement(component, isNodeType, r); + Map<String, ToscaRequirement> requirement = new HashMap<>(); + + requirement.put(pair.left, pair.right); + toscaRequirements.add(requirement); + }); + + log.debug("Finish convert Requirements for node type"); + } + } else { + log.debug("No Requirements for node type"); + } + return toscaRequirements; + } + + private Map<String, ToscaRequirement> convertRequirementsAsMap(Component component) { + Map<String, List<RequirementDefinition>> requirements = component.getRequirements(); + Map<String, ToscaRequirement> toscaRequirements = new HashMap<>(); + if (requirements != null) { + boolean isNodeType = ToscaUtils.isNodeType(component); + for (Map.Entry<String, List<RequirementDefinition>> entry : requirements.entrySet()) { + entry.getValue().stream().filter(r -> (!isNodeType || (isNodeType && component.getUniqueId().equals(r.getOwnerId())))).forEach(r -> { + ImmutablePair<String, ToscaRequirement> pair = convertRequirement(component, isNodeType, r); + toscaRequirements.put(pair.left, pair.right); + }); + + log.debug("Finish convert Requirements for node type"); + } + } else { + log.debug("No Requirements for node type"); + } + return toscaRequirements; + } + + private ImmutablePair<String, ToscaRequirement> convertRequirement(Component component, boolean isNodeType, RequirementDefinition r) { + String name = r.getName(); + if (!isNodeType) { + name = r.getOwnerName() + "." + name; + } + log.debug("the requirement {} belongs to resource {} ", name, component.getUniqueId()); + ToscaRequirement toscaRequirement = new ToscaRequirement(); + + List<Object> occurences = new ArrayList<>(); + occurences.add(Integer.valueOf(r.getMinOccurrences())); + if (r.getMaxOccurrences().equals(RequirementData.MAX_OCCURRENCES)) { + occurences.add(r.getMaxOccurrences()); + } else { + occurences.add(Integer.valueOf(r.getMaxOccurrences())); + } + toscaRequirement.setOccurrences(occurences); + // toscaRequirement.setOccurrences(createOcurrencesRange(requirementDefinition.getMinOccurrences(), + // requirementDefinition.getMaxOccurrences())); + toscaRequirement.setNode(r.getNode()); + toscaRequirement.setCapability(r.getCapability()); + toscaRequirement.setRelationship(r.getRelationship()); + + ImmutablePair<String, ToscaRequirement> pair = new ImmutablePair<String, ToscaRequirement>(name, toscaRequirement); + return pair; + } + + public Map<String, ToscaCapability> convertCapabilities(Component component, Map<String, DataTypeDefinition> dataTypes) { + Map<String, List<CapabilityDefinition>> capabilities = component.getCapabilities(); + Map<String, ToscaCapability> toscaCapabilities = new HashMap<>(); + if (capabilities != null) { + boolean isNodeType = ToscaUtils.isNodeType(component); + for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) { + entry.getValue().stream().filter(c -> (!isNodeType || (isNodeType && component.getUniqueId().equals(c.getOwnerId())))).forEach(c -> { + convertCapabilty(component, toscaCapabilities, isNodeType, c, dataTypes); + + }); + } + } else { + log.debug("No Capabilities for node type"); + } + + return toscaCapabilities; + } + + private void convertCapabilty(Component component, Map<String, ToscaCapability> toscaCapabilities, boolean isNodeType, CapabilityDefinition c, Map<String, DataTypeDefinition> dataTypes) { + String name = c.getName(); + if (!isNodeType) { + name = c.getOwnerName() + "." + name; + } + log.debug("the capabilty {} belongs to resource {} ", name, component.getUniqueId()); + ToscaCapability toscaCapability = new ToscaCapability(); + toscaCapability.setDescription(c.getDescription()); + toscaCapability.setType(c.getType()); + + List<Object> occurences = new ArrayList<>(); + occurences.add(Integer.valueOf(c.getMinOccurrences())); + if (c.getMaxOccurrences().equals(CapabilityData.MAX_OCCURRENCES)) { + occurences.add(c.getMaxOccurrences()); + } else { + occurences.add(Integer.valueOf(c.getMaxOccurrences())); + } + toscaCapability.setOccurrences(occurences); + + toscaCapability.setValid_source_types(c.getValidSourceTypes()); + List<ComponentInstanceProperty> properties = c.getProperties(); + if (properties != null && !properties.isEmpty()) { + Map<String, ToscaProperty> toscaProperties = new HashMap<>(); + for (PropertyDefinition property : properties) { + ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, true); + toscaProperties.put(property.getName(), toscaProperty); + } + toscaCapability.setProperties(toscaProperties); + } + toscaCapabilities.put(name, toscaCapability); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java new file mode 100644 index 0000000000..c8aa188e30 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java @@ -0,0 +1,649 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.io.IOException; +import org.apache.commons.codec.binary.Base64; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Triple; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic.ArtifactOperation; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; +import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.ServiceOperation; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.be.tosca.model.ToscaTemplate; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import org.openecomp.sdc.generator.data.Artifact; +import org.openecomp.sdc.generator.data.ArtifactType; +import org.openecomp.sdc.generator.data.GenerationData; +import org.openecomp.sdc.generator.impl.ArtifactGenerationServiceImpl; +import com.google.gson.Gson; + +import fj.data.Either; + +/** + * @author tg851x + * + */ +@org.springframework.stereotype.Component("csar-utils") +public class CsarUtils { + private static Logger log = LoggerFactory.getLogger(ToscaExportHandler.class.getName()); + + @Autowired + private ArtifactCassandraDao artifactCassandraDao; + @Autowired + private ComponentsUtils componentsUtils; + @Autowired + private ToscaExportHandler toscaExportUtils; + @Autowired + private ArtifactsBusinessLogic artifactsBusinessLogic; + @Autowired + protected ServiceOperation serviceOperation; + + @javax.annotation.Resource + private ServiceBusinessLogic serviceBusinessLogic; + + private Gson gson = new Gson(); + + private static final String DEFINITIONS_PATH = "Definitions/"; + private static final String ARTIFACTS_PATH = "Artifacts/"; + private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta"; + private static final String TOSCA_META_VERSION = "1.0"; + private static final String CSAR_VERSION = "1.1"; + + /** + * + * @param component + * @param getFromCS + * @param isInCertificationRequest + * @param shouldLock + * @param inTransaction + * @return + */ + public Either<byte[], ResponseFormat> createCsar(Component component, boolean getFromCS, boolean isInCertificationRequest, boolean shouldLock, boolean inTransaction) { + return createCsar(component, getFromCS, isInCertificationRequest, false, shouldLock, inTransaction); + } + + private Either<byte[], ResponseFormat> createCsar(Component component, boolean getFromCS, boolean isInCertificationRequest, boolean mockGenerator, boolean shouldLock, boolean inTransaction) { + final String CREATED_BY = component.getCreatorFullName(); + + String fileName; + Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts(); + ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); + fileName = artifactDefinition.getArtifactName(); + + String toscaBlock0 = createToscaBlock0(TOSCA_META_VERSION, CSAR_VERSION, CREATED_BY, fileName); + + byte[] toscaBlock0Byte = toscaBlock0.getBytes(); + + Either<byte[], ResponseFormat> generateCsarZipResponse = generateCsarZip(toscaBlock0Byte, component, getFromCS, isInCertificationRequest, mockGenerator, shouldLock, inTransaction); + + if (generateCsarZipResponse.isRight()) { + return Either.right(generateCsarZipResponse.right().value()); + } + + return Either.left(generateCsarZipResponse.left().value()); + } + + private Either<byte[], ResponseFormat> generateCsarZip(byte[] toscaBlock0Byte, Component component, boolean getFromCS, boolean isInCertificationRequest, boolean mockGenerator, boolean shouldLock, boolean inTransaction) { + + ZipOutputStream zip = null; + ByteArrayOutputStream out = null; + try { + out = new ByteArrayOutputStream(); + zip = new ZipOutputStream(out); + + zip.putNextEntry(new ZipEntry(TOSCA_META_PATH_FILE_NAME)); + zip.write(toscaBlock0Byte); + Either<ZipOutputStream, ResponseFormat> populateZip = populateZip(component, getFromCS, zip, isInCertificationRequest, mockGenerator, shouldLock, inTransaction); + if (populateZip.isRight()) { + log.debug("Failed to populate CSAR zip file {}", populateZip.right().value()); + return Either.right(populateZip.right().value()); + } + zip = populateZip.left().value(); + + zip.finish(); + byte[] byteArray = out.toByteArray(); + + return Either.left(byteArray); + } catch (IOException e) { + log.debug("createCsar failed IOexception", e); + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + return Either.right(responseFormat); + } finally { + try { + if (zip != null) { + zip.close(); + } + if (out != null) { + out.close(); + } + } catch (Exception e) { + log.error("Failed to close resources ", e); + } + } + } + + private Either<ZipOutputStream, ResponseFormat> populateZip(Component component, boolean getFromCS, ZipOutputStream zip, boolean isInCertificationRequest, boolean mockGenerator, boolean shouldLock, boolean inTransaction) { + + LifecycleStateEnum lifecycleState = component.getLifecycleState(); + String componentYaml = null; + Either<ToscaRepresentation, ToscaError> exportComponent = null; + byte[] mainYaml = null; + // <file name, esid, component> + List<Triple<String, String, Component>> dependencies = null; + List<ImmutablePair<Component, byte[]>> generatorInputs = new LinkedList<>(); + + String fileName; + Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts(); + ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); + fileName = artifactDefinition.getArtifactName(); + + if (getFromCS || !(lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + String esId = artifactDefinition.getEsId(); + Either<byte[], ActionStatus> fromCassandra = getFromCassandra(esId); + if (fromCassandra.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(fromCassandra.right().value()); + return Either.right(responseFormat); + } + mainYaml = fromCassandra.left().value(); + + } else { + exportComponent = toscaExportUtils.exportComponent(component); + if (exportComponent.isRight()) { + log.debug("exportComponent failed", exportComponent.right().value()); + ActionStatus convertedFromToscaError = componentsUtils.convertFromToscaError(exportComponent.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(convertedFromToscaError); + return Either.right(responseFormat); + } + ToscaRepresentation exportResult = exportComponent.left().value(); + componentYaml = exportResult.getMainYaml(); + mainYaml = componentYaml.getBytes(); + dependencies = exportResult.getDependencies(); + } + + try { + zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + fileName)); + zip.write(mainYaml); + + generatorInputs.add(new ImmutablePair<Component, byte[]>(component, mainYaml)); + + if (dependencies == null) { + Either<ToscaTemplate, ToscaError> dependenciesRes = toscaExportUtils.getDependencies(component); + if (dependenciesRes.isRight()) { + log.debug("Failed to retrieve dependencies for component {}, error {}", component.getUniqueId(), dependenciesRes.right().value()); + ActionStatus convertFromToscaError = componentsUtils.convertFromToscaError(dependenciesRes.right().value()); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(convertFromToscaError); + return Either.right(responseFormat); + } + dependencies = dependenciesRes.left().value().getDependencies(); + } + if (dependencies != null && !dependencies.isEmpty()) { + for (Triple<String, String, Component> d : dependencies) { + String esId = d.getMiddle(); + Component childComponent = d.getRight(); + fileName = d.getLeft(); + Either<byte[], ActionStatus> entryData = getEntryData(esId, childComponent); + + if (entryData.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(entryData.right().value()); + return Either.right(responseFormat); + } + + byte[] content = entryData.left().value(); + zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + fileName)); + zip.write(content); + + generatorInputs.add(new ImmutablePair<Component, byte[]>(childComponent, content)); + } + } + + List<ArtifactDefinition> aiiArtifactList = new LinkedList<>(); + // Artifact Generation + if (component.getComponentType() == ComponentTypeEnum.SERVICE && (lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + Either<List<ArtifactDefinition>, ResponseFormat> handleAAIArtifacts = handleAAIArtifacts(component, zip, mockGenerator, shouldLock, inTransaction, generatorInputs); + + if (handleAAIArtifacts.isLeft()) { + aiiArtifactList = handleAAIArtifacts.left().value(); + } else { + log.debug("AAI Artifacts handling failed"); + return Either.right(handleAAIArtifacts.right().value()); + } + + if (isInCertificationRequest) { + Either<ActionStatus, ResponseFormat> handleAllAAIArtifactsInDataModel = handleAllAAIArtifactsInDataModel(component, aiiArtifactList, shouldLock, inTransaction); + + if (handleAllAAIArtifactsInDataModel.isRight()) { + log.debug("AAI Artifacts handling (create, update, delete) failed"); + return Either.right(handleAllAAIArtifactsInDataModel.right().value()); + } + } + + } + + // Collecting All Deployment Artifacts + Either<ZipOutputStream, ActionStatus> collectAndWriteToScarDeploymentArtifacts = collectAndWriteToScarDeploymentArtifacts(zip, component, aiiArtifactList); + + if (collectAndWriteToScarDeploymentArtifacts.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } catch (IOException e) { + log.debug("Failed to create CSAR zip for component {}", component.getUniqueId(), e); + } + + return Either.left(zip); + } + + private Either<ZipOutputStream, ActionStatus> collectAndWriteToScarDeploymentArtifacts(ZipOutputStream zip, Component component, List<ArtifactDefinition> aiiArtifactList) throws IOException { + + Collection<ArtifactDefinition> deploymentArtifactsToAdd = null; + Collection<ArtifactDefinition> allArtifactsToAdd = new LinkedList<>(); + + if (component.getComponentType() == ComponentTypeEnum.SERVICE) { + Either<Service, StorageOperationStatus> getServiceResponse = serviceOperation.getService(component.getUniqueId()); + + if (getServiceResponse.isLeft()) { + Service service = getServiceResponse.left().value(); + + if (!aiiArtifactList.isEmpty()) { + deploymentArtifactsToAdd = service.getDeploymentArtifacts().values().stream().filter(e -> e.getGenerated() == null || !e.getGenerated()).collect(Collectors.toList()); + allArtifactsToAdd.addAll(aiiArtifactList); + allArtifactsToAdd.addAll(deploymentArtifactsToAdd); + } else { + allArtifactsToAdd.addAll(service.getDeploymentArtifacts().values()); + } + } + } + + if (!allArtifactsToAdd.isEmpty()) { + + for (ArtifactDefinition deploymentArtifactDefinition : allArtifactsToAdd) { + String artifactFileName = deploymentArtifactDefinition.getArtifactName(); + byte[] payloadData = deploymentArtifactDefinition.getPayloadData(); + + if (payloadData == null) { + String esId = deploymentArtifactDefinition.getEsId(); + if (esId != null) { + Either<byte[], ActionStatus> fromCassandra = getFromCassandra(esId); + + if (fromCassandra.isRight()) { + return Either.right(fromCassandra.right().value()); + } + payloadData = fromCassandra.left().value(); + } else { + log.debug("Artifact {} payload not supplied in ArtifactDefinition and not found in DB", artifactFileName); + continue; + } + } + + byte[] decodedPayload = null; + + if (Base64.isBase64(payloadData)) { + // decodedPayload = Base64.getDecoder().decode(payloadData); + decodedPayload = Base64.decodeBase64(payloadData); + } else { + decodedPayload = payloadData; + } + + zip.putNextEntry(new ZipEntry(ARTIFACTS_PATH + artifactFileName)); + zip.write(decodedPayload); + } + } + + return Either.left(zip); + } + + private Either<List<ArtifactDefinition>, ResponseFormat> handleAAIArtifacts(Component component, ZipOutputStream zip, boolean mockGenerator, boolean shouldLock, boolean inTransaction, List<ImmutablePair<Component, byte[]>> generatorInputs) { + + ComponentTypeEnum componentType = component.getComponentType(); + List<Artifact> generatedArtifacts = null; + List<ArtifactDefinition> aaiArtifacts = null; + + if (componentType == ComponentTypeEnum.SERVICE && !generatorInputs.isEmpty()) { + List<Artifact> convertedGeneratorInputs = convertToGeneratorArtifactsInput(generatorInputs); + + Either<List<Artifact>, ResponseFormat> generatorResponse; + + if (mockGenerator) { + generatorResponse = artifactGenerator(convertedGeneratorInputs, ArtifactType.OTHER, component); + } else { + generatorResponse = artifactGenerator(convertedGeneratorInputs, ArtifactType.AAI, component); + } + + if (generatorResponse.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.AAI_ARTIFACT_GENERATION_FAILED, component.getComponentType().getValue(), component.getName(), generatorResponse.toString()); + return Either.right(responseFormat); + } + + generatedArtifacts = generatorResponse.left().value(); + + aaiArtifacts = convertToArtifactDefinitionFromArtifactGeneratedData(generatedArtifacts); + + } + + return Either.left(aaiArtifacts); + } + + private Either<ActionStatus, ResponseFormat> handleAllAAIArtifactsInDataModel(Component component, List<ArtifactDefinition> artifactsFromAAI, boolean shouldLock, boolean inTransaction) { + + Either<ActionStatus, ResponseFormat> handleAAIArtifactsResponse = null; + User lastComponentUpdater = null; + + List<ArtifactDefinition> aaiArtifatcsToCreate = getAAIArtifatcsForCreate(artifactsFromAAI, component); + List<ArtifactDefinition> aaiArtifatcsToDelete = getAAIArtifatcsForDelete(artifactsFromAAI, component); + List<ArtifactDefinition> aaiArtifatcsToUpdate = getAAIArtifatcsForUpdate(artifactsFromAAI, component); + + String lastUpdaterUserId = component.getLastUpdaterUserId(); + Either<User, ResponseFormat> validateUserExists = artifactsBusinessLogic.validateUserExists(lastUpdaterUserId, "CSAR creation util", true); + + if (validateUserExists.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.AAI_ARTIFACT_GENERATION_FAILED, component.getComponentType().getValue(), component.getName(), "User not found"); + return Either.right(responseFormat); + } + + lastComponentUpdater = validateUserExists.left().value(); + + handleAAIArtifactsResponse = handleAAIArtifactsInDataModelByOperationType(component, aaiArtifatcsToDelete, ArtifactOperation.Delete, lastComponentUpdater, shouldLock, inTransaction); + + if (handleAAIArtifactsResponse.isRight()) { + return handleAAIArtifactsResponse; + } + + handleAAIArtifactsResponse = handleAAIArtifactsInDataModelByOperationType(component, aaiArtifatcsToCreate, ArtifactOperation.Create, lastComponentUpdater, shouldLock, inTransaction); + + if (handleAAIArtifactsResponse.isRight()) { + return handleAAIArtifactsResponse; + } + + return handleAAIArtifactsInDataModelByOperationType(component, aaiArtifatcsToUpdate, ArtifactOperation.Update, lastComponentUpdater, shouldLock, inTransaction); + } + + private List<ArtifactDefinition> getAAIArtifatcsForUpdate(List<ArtifactDefinition> artifactsFromAAI, Component component) { + + Set<String> componetDeploymentArtifactLables = component.getDeploymentArtifacts().keySet(); + Set<String> componetInformationalArtifactLables = component.getArtifacts().keySet(); + + List<ArtifactDefinition> artifactsAaiUpdate = artifactsFromAAI.stream().filter(e -> (componetDeploymentArtifactLables.contains(e.getArtifactLabel()) || componetInformationalArtifactLables.contains(e.getArtifactLabel()))) + .filter(e -> checkAaiForUpdate(component, e)).collect(Collectors.toList()); + + return artifactsAaiUpdate; + } + + private boolean checkAaiForUpdate(Component component, ArtifactDefinition artifactDefinition) { + ArtifactDefinition artifactDefinitionComp = component.getDeploymentArtifacts().get(artifactDefinition.getArtifactLabel()); + + if (artifactDefinitionComp == null) { + log.warn("Failed to get {} artifact", artifactDefinition.getArtifactLabel()); + return false; + } + + // Old Artifacts before the generated flag introduction if contains "aai" ignore case prefix updated + if (artifactDefinitionComp.getGenerated() == null) { + if (artifactDefinitionComp.getArtifactLabel().toLowerCase().startsWith("aai")) { + return true; + } else { + log.warn("The artifact {} flag is null but AAI prefix is abssent Not updated", artifactDefinition.getArtifactLabel()); + } + } else { + if (artifactDefinition.getGenerated()) { + return true; + } else { + log.warn("Generated artifact {} was already uploaded manually", artifactDefinition.getArtifactLabel()); + } + } + return false; + } + + private List<ArtifactDefinition> getAAIArtifatcsForDelete(List<ArtifactDefinition> artifactsFromAAI, Component component) { + + Set<String> aaiLabels = artifactsFromAAI.stream().map(e -> e.getArtifactLabel()).collect(Collectors.toSet()); + + List<ArtifactDefinition> artifactsForDeleteDeployment = component.getDeploymentArtifacts().values().stream(). + // Filter Out Artifacts that are not contained in artifacts returned + // from AAI API + filter(e -> !aaiLabels.contains(e.getArtifactLabel())).collect(Collectors.toList()); + + List<ArtifactDefinition> artifactsForDeleteInformational = component.getArtifacts().values().stream(). + // Filter Out Artifacts that are not contained in artifacts returned + // from AAI API + filter(e -> !aaiLabels.contains(e.getArtifactLabel())).collect(Collectors.toList()); + + artifactsForDeleteDeployment.addAll(artifactsForDeleteInformational); + + return artifactsForDeleteDeployment.stream().filter(e -> (e.getGenerated() != null && e.getGenerated().equals(Boolean.TRUE)) || (e.getGenerated() == null && e.getArtifactLabel().toLowerCase().startsWith("aai"))).collect(Collectors.toList()); + } + + private List<ArtifactDefinition> getAAIArtifatcsForCreate(List<ArtifactDefinition> artifactsFromAAI, Component component) { + + Set<String> componentDeploymentLabels = component.getDeploymentArtifacts().keySet(); + Set<String> componentInfoLabels = component.getArtifacts().keySet(); + + // If the artifact label does not exist in the service - + // store the artifact (generate uuid and version, "generated" flag is TRUE) + return artifactsFromAAI.stream().filter(e -> !componentDeploymentLabels.contains(e.getArtifactLabel()) && !componentInfoLabels.contains(e.getArtifactLabel())).collect(Collectors.toList()); + } + + private Either<ActionStatus, ResponseFormat> handleAAIArtifactsInDataModelByOperationType(Component component, List<ArtifactDefinition> generatedArtifactsDefinitions, ArtifactOperation operationType, User user, boolean shouldLock, + boolean inTransaction) { + + String componentUniqueId = component.getUniqueId(); + ComponentTypeEnum componentType = component.getComponentType(); + + for (ArtifactDefinition artDef : generatedArtifactsDefinitions) { + String data = gson.toJson(artDef); + String dataMD5 = GeneralUtility.calculateMD5ByString(data); + String artifactUniqueId = null; + + if (operationType.equals(ArtifactOperation.Update) || operationType.equals(ArtifactOperation.Delete)) { + String artifactLabel = artDef.getArtifactLabel(); + ArtifactDefinition artifactDefinition = component.getDeploymentArtifacts().get(artifactLabel); + if (artifactDefinition != null) { + artifactUniqueId = artifactDefinition.getUniqueId(); + } + } + + Either<Either<ArtifactDefinition, Operation>, ResponseFormat> validateAndHandleArtifact = artifactsBusinessLogic.validateAndHandleArtifact(componentUniqueId, componentType, operationType, artifactUniqueId, artDef, dataMD5, data, null, + null, null, user, component, shouldLock, inTransaction); + + if (validateAndHandleArtifact.isRight()) { + if (ArtifactOperation.Create == operationType || ArtifactOperation.Update == operationType) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.AAI_ARTIFACT_GENERATION_FAILED, componentType.getValue(), component.getName(), validateAndHandleArtifact.right().value().toString()); + + Either.right(responseFormat); + } else { + log.warn("Generated artifact {} could not be deleted", artDef.getArtifactLabel()); + } + } + } + + return Either.left(ActionStatus.OK); + } + + private List<ArtifactDefinition> convertToArtifactDefinitionFromArtifactGeneratedData(List<Artifact> generatorOutput) { + List<ArtifactDefinition> artifactDefList = new LinkedList<>(); + + for (Artifact artifact : generatorOutput) { + ArtifactDefinition newEntry = new ArtifactDefinition(); + newEntry.setArtifactName(artifact.getName()); + newEntry.setArtifactType(artifact.getType()); + newEntry.setArtifactGroupType(ArtifactGroupTypeEnum.findType(artifact.getGroupType())); + newEntry.setDescription(artifact.getDescription()); + + // Normalizing the artifact label to match those stored in DB + String normalizeArtifactLabel = ValidationUtils.normalizeArtifactLabel(artifact.getLabel()); + newEntry.setArtifactLabel(normalizeArtifactLabel); + newEntry.setPayload(artifact.getPayload()); + newEntry.setArtifactChecksum(artifact.getChecksum()); + // Flag that set to true in case that the artifact is generated by AI&I generator + newEntry.setGenerated(Boolean.TRUE); + + artifactDefList.add(newEntry); + } + + return artifactDefList; + } + + // List<ImmutablePair<Component, byte[] artifactBytes>> + // artifact stored by label + private List<Artifact> convertToGeneratorArtifactsInput(List<ImmutablePair<Component, byte[]>> inputs) { + List<Artifact> listOfArtifactsInput = new LinkedList<>(); + for (ImmutablePair<Component, byte[]> triple : inputs) { + Component component = triple.getLeft(); + + Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts(); + ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); + + String artifactName = artifactDefinition.getArtifactName(); + String artifactType = artifactDefinition.getArtifactType(); + String artifactGroupType = artifactDefinition.getArtifactGroupType().getType(); + String artifactDescription = artifactDefinition.getDescription(); + String artifactLabel = artifactDefinition.getArtifactLabel(); + byte[] right = triple.getRight(); + // The md5 calculated on the uncoded data + String md5Hex = DigestUtils.md5Hex(right); + // byte[] payload = Base64.getEncoder().encode(right); + byte[] payload = Base64.encodeBase64(right); + String artifactVersion = artifactDefinition.getArtifactVersion(); + + Artifact convertedArtifact = new Artifact(artifactType, artifactGroupType, md5Hex, payload); + convertedArtifact.setName(artifactName); + convertedArtifact.setDescription(artifactDescription); + convertedArtifact.setLabel(artifactLabel); + convertedArtifact.setVersion(artifactVersion); + + listOfArtifactsInput.add(convertedArtifact); + } + + return listOfArtifactsInput; + } + + private Either<byte[], ActionStatus> getEntryData(String esId, Component childComponent) { + byte[] content; + if (esId == null || esId.isEmpty()) { + Either<ToscaRepresentation, ToscaError> exportRes = toscaExportUtils.exportComponent(childComponent); + if (exportRes.isRight()) { + log.debug("Failed to export tosca template for child component {} error {}", childComponent.getUniqueId(), exportRes.right().value()); + return Either.right(componentsUtils.convertFromToscaError(exportRes.right().value())); + } + content = exportRes.left().value().getMainYaml().getBytes(); + } else { + Either<byte[], ActionStatus> fromCassandra = getFromCassandra(esId); + if (fromCassandra.isRight()) { + return Either.right(fromCassandra.right().value()); + } else { + content = fromCassandra.left().value(); + } + } + return Either.left(content); + } + + private Either<byte[], ActionStatus> getFromCassandra(String esId) { + Either<ESArtifactData, CassandraOperationStatus> artifactResponse = artifactCassandraDao.getArtifact(esId); + + if (artifactResponse.isRight()) { + log.debug("In createCsar fetching of artifact from CS failed"); + log.debug("Failed to fetch from Cassandra by id {} error {} ", esId, artifactResponse.right().value()); + + StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(artifactResponse.right().value()); + ActionStatus convertedFromStorageResponse = componentsUtils.convertFromStorageResponse(storageStatus); + return Either.right(convertedFromStorageResponse); + } else { + ESArtifactData artifactData = artifactResponse.left().value(); + return Either.left(artifactData.getDataAsArray()); + + } + } + + private String createToscaBlock0(String metaFileVersion, String csarVersion, String createdBy, String entryDef) { + final String BLOCK_0_TEMPLATE = "TOSCA-Meta-File-Version: %s\nCSAR-Version: %s\nCreated-By: %s\nEntry-Definitions: Definitions/%s\n"; + String readyBlock = String.format(BLOCK_0_TEMPLATE, metaFileVersion, csarVersion, createdBy, entryDef); + return readyBlock; + } + + private Either<List<Artifact>, ResponseFormat> artifactGenerator(List<Artifact> artifactList, ArtifactType type, Component component) { + + ArtifactGenerationServiceImpl artifactGenerationServiceImpl = new ArtifactGenerationServiceImpl(); + ArtifactTypes artifactTypes = new ArtifactTypes(); + List<ArtifactType> artifactTypesList = new LinkedList<>(); + ArtifactType otherType; + + if (type == null) { + otherType = ArtifactType.OTHER; + } else { + otherType = type; + } + + artifactTypesList.add(otherType); + artifactTypes.setArtifactTypes(artifactTypesList); + + String configJson = gson.toJson(artifactTypes); + GenerationData generatedArtifacts = artifactGenerationServiceImpl.generateArtifact(artifactList, configJson); + + Map<String, List<String>> errorData = generatedArtifacts.getErrorData(); + + if (!errorData.isEmpty()) { + Set<String> keySet = errorData.keySet(); + + for (String key : keySet) { + List<String> errorList = errorData.get(key); + log.debug("The Artifact Generator Failed - {} with following: {}", key, errorList); + } + + ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.AAI_ARTIFACT_GENERATION_FAILED, component.getComponentType().getValue(), component.getName(), errorData.toString()); + return Either.right(responseFormat); + } + + return Either.left(generatedArtifacts.getResultData()); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java new file mode 100644 index 0000000000..544b85361d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java @@ -0,0 +1,189 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.io.StringReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.converters.ToscaMapValueConverter; +import org.openecomp.sdc.be.model.tosca.converters.ToscaValueConverter; +import org.openecomp.sdc.be.tosca.model.EntrySchema; +import org.openecomp.sdc.be.tosca.model.ToscaNodeType; +import org.openecomp.sdc.be.tosca.model.ToscaProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.gson.stream.JsonReader; + +import fj.data.Either; + +public class PropertyConvertor { + private static PropertyConvertor instance; + private JsonParser jsonParser = new JsonParser(); + private static Logger log = LoggerFactory.getLogger(PropertyConvertor.class.getName()); + + protected PropertyConvertor() { + + } + + public static synchronized PropertyConvertor getInstance() { + if (instance == null) { + instance = new PropertyConvertor(); + } + return instance; + } + + public Either<ToscaNodeType, ToscaError> convertProperties(Component component, ToscaNodeType toscaNodeType, Map<String, DataTypeDefinition> dataTypes) { + + if (component instanceof Resource) { + Resource resource = (Resource) component; + List<PropertyDefinition> props = resource.getProperties(); + if (props != null) { + Map<String, ToscaProperty> properties = new HashMap<>(); + + // take only the properties of this resource + props.stream().filter(p -> component.getUniqueId().equals(p.getParentUniqueId())).forEach(property -> { + ToscaProperty prop = convertProperty(dataTypes, property, false); + + properties.put(property.getName(), prop); + + }); + if (!properties.isEmpty()) { + toscaNodeType.setProperties(properties); + } + } + } + return Either.left(toscaNodeType); + } + + public ToscaProperty convertProperty(Map<String, DataTypeDefinition> dataTypes, PropertyDefinition property, boolean isCapabiltyProperty) { + ToscaProperty prop = new ToscaProperty(); + + String innerType = null; + SchemaDefinition schema = property.getSchema(); + if (schema != null && schema.getProperty() != null && schema.getProperty().getType() != null && !schema.getProperty().getType().isEmpty()) { + innerType = schema.getProperty().getType(); + EntrySchema eschema = new EntrySchema(); + eschema.setType(innerType); + eschema.setDescription(schema.getProperty().getDescription()); + prop.setEntry_schema(eschema); + } + log.debug("try to convert property {} from type {} with default value {}", property.getName(), property.getType(), property.getDefaultValue()); + prop.setDefaultp(convertToToscaObject(property.getType(), property.getDefaultValue(), innerType, dataTypes)); + prop.setType(property.getType()); + prop.setDescription(property.getDescription()); + if (isCapabiltyProperty) { + prop.setStatus(property.getStatus()); + prop.setRequired(property.isRequired()); + } + return prop; + } + + public Object convertToToscaObject(String propertyType, String value, String innerType, Map<String, DataTypeDefinition> dataTypes) { + log.debug("try to convert propertyType {} , value {}, innerType {}", propertyType, value, innerType); + if (value == null) { + return value; + } + + ToscaMapValueConverter mapConverterInst = ToscaMapValueConverter.getInstance(); + ToscaValueConverter innerConverter = null; + Boolean isScalar = true; + + ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType); + if (type == null) { + log.debug("isn't prederfined type, get from all data types"); + DataTypeDefinition dataTypeDefinition = dataTypes.get(propertyType); + if (innerType == null) { + innerType = propertyType; + } + + if ((type = mapConverterInst.isScalarType(dataTypeDefinition)) != null) { + log.debug("This is scalar type. get suitable converter for type {}", type); + innerConverter = type.getValueConverter(); + } else { + isScalar = false; + } + } else { + ToscaPropertyType typeIfScalar = ToscaPropertyType.getTypeIfScalar(type.getType()); + if (typeIfScalar == null) { + isScalar = false; + } + + innerConverter = type.getValueConverter(); + if (ToscaPropertyType.STRING.equals(type) && value.startsWith("/")) { + return innerConverter.convertToToscaValue(value, innerType, dataTypes); + } + } + JsonElement jsonElement = null; + try { + StringReader reader = new StringReader(value); + JsonReader jsonReader = new JsonReader(reader); + jsonReader.setLenient(true); + + jsonElement = jsonParser.parse(jsonReader); + + if (value.equals("")) { + return value; + } + + if (jsonElement.isJsonPrimitive() && isScalar) { + log.debug("It's well defined type. convert it"); + ToscaValueConverter converter = type.getValueConverter(); + return converter.convertToToscaValue(value, innerType, dataTypes); + } else { + log.debug("It's data type or inputs in primitive type. convert as map"); + Object convertedValue; + if (innerConverter != null && (ToscaPropertyType.MAP.equals(type) || ToscaPropertyType.LIST.equals(type))) { + convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes); + } else { + if (isScalar) { + // complex json for scalar type + convertedValue = mapConverterInst.handleComplexJsonValue(jsonElement); + } else { + if (innerConverter != null) { + convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes); + } else { + convertedValue = mapConverterInst.convertDataTypeToToscaMap(innerType, dataTypes, innerConverter, isScalar, jsonElement); + } + } + } + return convertedValue; + } + + } catch (JsonSyntaxException e) { + log.debug("convertToToscaValue failed to parse json value :", e); + return null; + } + + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaError.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaError.java new file mode 100644 index 0000000000..94dd559d2d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaError.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +public enum ToscaError { + + NODE_TYPE_CAPABILITY_ERROR, NOT_SUPPORTED_TOSCA_TYPE, NODE_TYPE_REQUIREMENT_ERROR, GENERAL_ERROR +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java new file mode 100644 index 0000000000..1bf940ffc0 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -0,0 +1,629 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.beans.IntrospectionException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.apache.commons.lang3.tuple.Triple; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datamodel.utils.ArtifactUtils; +import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.GroupProperty; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.operations.api.IResourceOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.tosca.model.IToscaMetadata; +import org.openecomp.sdc.be.tosca.model.SubstitutionMapping; +import org.openecomp.sdc.be.tosca.model.ToscaCapability; +import org.openecomp.sdc.be.tosca.model.ToscaGroupTemplate; +import org.openecomp.sdc.be.tosca.model.ToscaMetadata; +import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate; +import org.openecomp.sdc.be.tosca.model.ToscaNodeType; +import org.openecomp.sdc.be.tosca.model.ToscaProperty; +import org.openecomp.sdc.be.tosca.model.ToscaTemplate; +import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement; +import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate; +import org.openecomp.sdc.be.tosca.model.VfModuleToscaMetadata; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.DumperOptions.FlowStyle; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.introspector.BeanAccess; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.introspector.PropertyUtils; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.Tag; +import org.yaml.snakeyaml.representer.Represent; +import org.yaml.snakeyaml.representer.Representer; + +import fj.data.Either; + +@org.springframework.stereotype.Component("tosca-export-handler") +public class ToscaExportHandler { + + @Autowired + private ApplicationDataTypeCache dataTypeCache; + + @Autowired + private IResourceOperation resourceOperation; + + private CapabiltyRequirementConvertor capabiltyRequirementConvertor = CapabiltyRequirementConvertor.getInstance(); + private PropertyConvertor propertyConvertor = PropertyConvertor.getInstance(); + + private static Logger log = LoggerFactory.getLogger(ToscaExportHandler.class.getName()); + + public static final String TOSCA_VERSION = "tosca_simple_yaml_1_0"; + public static final String SERVICE_NODE_TYPE_PREFIX = "org.openecomp.service."; + public static final String IMPORTS_FILE_KEY = "file"; + public static final String TOSCA_TEMPLATE_NAME = "-template.yml"; + public static final String ASSET_TOSCA_TEMPLATE = "assettoscatemplate"; + public static final String VF_MODULE_TYPE_KEY = "vf_module_type"; + public static final String VF_MODULE_DESC_KEY = "vf_module_description"; + public static final String VOLUME_GROUP_KEY = "volume_group"; + public static final String VF_MODULE_TYPE_BASE = "Base"; + public static final String VF_MODULE_TYPE_EXPANSION = "Expansion"; + + public Either<ToscaRepresentation, ToscaError> exportComponent(Component component) { + + Either<ToscaTemplate, ToscaError> toscaTemplateRes = convertToToscaTemplate(component); + if (toscaTemplateRes.isRight()) { + return Either.right(toscaTemplateRes.right().value()); + } + + CustomRepresenter representer = new CustomRepresenter(); + DumperOptions options = new DumperOptions(); + options.setAllowReadOnlyProperties(false); + options.setPrettyFlow(true); + + options.setDefaultFlowStyle(FlowStyle.FLOW); + options.setCanonical(false); + + ToscaTemplate toscaTemplate = toscaTemplateRes.left().value(); + representer.addClassTag(toscaTemplate.getClass(), Tag.MAP); + + representer.setPropertyUtils(new UnsortedPropertyUtils()); + Yaml yaml = new Yaml(representer, options); + + String yamlAsString = yaml.dumpAsMap(toscaTemplate); + + StringBuilder sb = new StringBuilder(); + sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactHeader()); + sb.append(yamlAsString); + sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactFooter()); + + ToscaRepresentation toscaRepresentation = new ToscaRepresentation(); + toscaRepresentation.setMainYaml(sb.toString()); + toscaRepresentation.setDependencies(toscaTemplate.getDependencies()); + + return Either.left(toscaRepresentation); + } + + public Either<ToscaTemplate, ToscaError> getDependencies(Component component) { + ToscaTemplate toscaTemplate = new ToscaTemplate(null); + Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports = fillImports(component, toscaTemplate); + if (fillImports.isRight()) { + return Either.right(fillImports.right().value()); + } + return Either.left(fillImports.left().value().left); + } + + private Either<ToscaTemplate, ToscaError> convertToToscaTemplate(Component component) { + log.debug("start tosca export for {}", component.getUniqueId()); + ToscaTemplate toscaTemplate = new ToscaTemplate(TOSCA_VERSION); + + toscaTemplate.setMetadata(convertMetadata(component, false)); + + Map<String, ToscaNodeType> node_types = new HashMap<>(); + if (ToscaUtils.isNodeType(component)) { + log.debug("convert component as node type"); + return convertNodeType(component, toscaTemplate, node_types); + } else { + log.debug("convert component as topology template"); + return convertToscaTemplate(component, toscaTemplate); + } + + } + + private Either<ToscaTemplate, ToscaError> convertToscaTemplate(Component component, ToscaTemplate toscaNode) { + + Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> importsRes = fillImports(component, toscaNode); + if (importsRes.isRight()) { + return Either.right(importsRes.right().value()); + } + toscaNode = importsRes.left().value().left; + + Map<String, Component> componentCache = importsRes.left().value().right; + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); + if (dataTypesEither.isRight()) { + log.debug("Failed to retrieve all data types {}", dataTypesEither.right().value()); + return Either.right(ToscaError.GENERAL_ERROR); + } + Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value(); + + ToscaTopolgyTemplate topology_template = new ToscaTopolgyTemplate(); + + Either<ToscaTopolgyTemplate, ToscaError> inputs = fillInputs(component, topology_template, dataTypes); + if (inputs.isRight()) { + return Either.right(inputs.right().value()); + } + topology_template = inputs.left().value(); + + List<ComponentInstance> componentInstances = component.getComponentInstances(); + Map<String, List<ComponentInstanceProperty>> componentInstancesProperties = component.getComponentInstancesProperties(); + List<GroupDefinition> groups = component.getGroups(); + if (componentInstances != null && !componentInstances.isEmpty()) { + + Either<Map<String, ToscaNodeTemplate>, ToscaError> node_templates = convertNodeTemplates(component, componentInstances, componentInstancesProperties, componentCache, dataTypes); + if (node_templates.isRight()) { + return Either.right(node_templates.right().value()); + } + log.debug("node templates converted"); + + topology_template.setNode_templates(node_templates.left().value()); + } + if (groups != null && !groups.isEmpty()) { + Map<String, ToscaGroupTemplate> groupsMap = new HashMap<String, ToscaGroupTemplate>(); + for (GroupDefinition group : groups) { + ToscaGroupTemplate toscaGroup = convertGroup(group, component); + groupsMap.put(group.getName(), toscaGroup); + + } + topology_template.setGroups(groupsMap); + log.debug("groups converted"); + + } + + SubstitutionMapping substitutionMapping = new SubstitutionMapping(); + String toscaResourceName = null; + switch (component.getComponentType()) { + case RESOURCE: + toscaResourceName = ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition()).getToscaResourceName(); + break; + case SERVICE: + toscaResourceName = SERVICE_NODE_TYPE_PREFIX + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName(); + break; + default: + log.debug("Not supported component type {}", component.getComponentType()); + return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE); + } + substitutionMapping.setNode_type(toscaResourceName); + + Either<SubstitutionMapping, ToscaError> capabilities = convertCapabilities(component, substitutionMapping, dataTypes); + if (capabilities.isRight()) { + return Either.right(capabilities.right().value()); + } + substitutionMapping = capabilities.left().value(); + + Either<SubstitutionMapping, ToscaError> requirements = capabiltyRequirementConvertor.convertRequirements(component, substitutionMapping); + if (requirements.isRight()) { + return Either.right(requirements.right().value()); + } + substitutionMapping = requirements.left().value(); + + topology_template.setSubstitution_mappings(substitutionMapping); + + toscaNode.setTopology_template(topology_template); + return Either.left(toscaNode); + } + + private Either<ToscaTopolgyTemplate, ToscaError> fillInputs(Component component, ToscaTopolgyTemplate topology_template, Map<String, DataTypeDefinition> dataTypes) { + if (log.isDebugEnabled()) + log.debug("fillInputs for component {}", component.getUniqueId()); + List<InputDefinition> inputDef = component.getInputs(); + Map<String, ToscaProperty> inputs = new HashMap<>(); + + if (inputDef != null) { + inputDef.forEach(i -> { + ToscaProperty property = propertyConvertor.convertProperty(dataTypes, i, false); + inputs.put(i.getName(), property); + }); + if (inputs != null && !inputs.isEmpty()) { + topology_template.setInputs(inputs); + } + } + return Either.left(topology_template); + } + + private ToscaMetadata convertMetadata(Component component, boolean isInstance) { + ToscaMetadata toscaMetadata = new ToscaMetadata(); + toscaMetadata.setName(component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); + toscaMetadata.setInvariantUUID(component.getInvariantUUID()); + toscaMetadata.setUUID(component.getUUID()); + toscaMetadata.setDescription(component.getDescription()); + + List<CategoryDefinition> categories = component.getCategories(); + CategoryDefinition categoryDefinition = categories.get(0); + toscaMetadata.setCategory(categoryDefinition.getName()); + + if (isInstance) { + toscaMetadata.setVersion(component.getVersion()); + } + switch (component.getComponentType()) { + case RESOURCE: + Resource resource = (Resource) component; + toscaMetadata.setType(resource.getResourceType().name()); + toscaMetadata.setSubcategory(categoryDefinition.getSubcategories().get(0).getName()); + if (!isInstance) { + toscaMetadata.setResourceVendor(resource.getVendorName()); + toscaMetadata.setResourceVendorRelease(resource.getVendorRelease()); + } + break; + case SERVICE: + toscaMetadata.setType(component.getComponentType().getValue()); + if (!isInstance) { + toscaMetadata.setServiceEcompNaming(false); + toscaMetadata.setServiceHoming(false); + } + break; + default: + log.debug("Not supported component type {}", component.getComponentType()); + } + return toscaMetadata; + } + + private Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports(Component component, ToscaTemplate toscaTemplate) { + Map<String, Component> componentCache = new HashMap<>(); + if (!ToscaUtils.isNodeType(component)) { + List<ComponentInstance> componentInstances = component.getComponentInstances(); + if (componentInstances != null && !componentInstances.isEmpty()) { + List<Map<String, Map<String, String>>> imports = new LinkedList<Map<String, Map<String, String>>>(); + List<Triple<String, String, Component>> dependecies = new ArrayList<>(); + + componentInstances.forEach(ci -> { + createDependency(componentCache, imports, dependecies, ci); + }); + toscaTemplate.setImports(imports); + toscaTemplate.setDependencies(dependecies); + } + } else { + log.debug("currently imports supported for VF and service only"); + } + return Either.left(new ImmutablePair<ToscaTemplate, Map<String, Component>>(toscaTemplate, componentCache)); + } + + private void createDependency(Map<String, Component> componentCache, List<Map<String, Map<String, String>>> imports, List<Triple<String, String, Component>> dependecies, ComponentInstance ci) { + Map<String, String> files = new HashMap<>(); + Map<String, Map<String, String>> importsListMember = new HashMap<>(); + + Component componentRI = componentCache.get(ci.getComponentUid()); + if (componentRI == null) { + // all resource must be only once! + Either<Resource, StorageOperationStatus> resource = resourceOperation.getResource(ci.getComponentUid(), true); + if (resource.isRight()) { + log.debug("Failed to fetch resource with id {} for instance {}"); + } + Resource fetchedComponent = resource.left().value(); + componentCache.put(fetchedComponent.getUniqueId(), fetchedComponent); + componentRI = fetchedComponent; + + Map<String, ArtifactDefinition> toscaArtifacts = componentRI.getToscaArtifacts(); + ArtifactDefinition artifactDefinition = toscaArtifacts.get(ASSET_TOSCA_TEMPLATE); + if (artifactDefinition != null) { + String artifactName = artifactDefinition.getArtifactName(); + files.put(IMPORTS_FILE_KEY, artifactName); + importsListMember.put(ci.getComponentName(), files); + dependecies.add(new ImmutableTriple<String, String, Component>(artifactName, artifactDefinition.getEsId(), fetchedComponent)); + } + } + if (!importsListMember.isEmpty()) { + imports.add(importsListMember); + } + } + + private Either<ToscaTemplate, ToscaError> convertNodeType(Component component, ToscaTemplate toscaNode, Map<String, ToscaNodeType> node_types) { + log.debug("start convert node type for {}", component.getUniqueId()); + ToscaNodeType toscaNodeType = createNodeType(component); + + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); + if (dataTypesEither.isRight()) { + log.debug("Failed to fetch all data types :", dataTypesEither.right().value()); + return Either.right(ToscaError.GENERAL_ERROR); + } + + Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value(); + Either<ToscaNodeType, ToscaError> properties = propertyConvertor.convertProperties(component, toscaNodeType, dataTypes); + if (properties.isRight()) { + return Either.right(properties.right().value()); + } + toscaNodeType = properties.left().value(); + log.debug("Properties converted for {}", component.getUniqueId()); + + Either<ToscaNodeType, ToscaError> capabilities = convertCapabilities(component, toscaNodeType, dataTypes); + if (capabilities.isRight()) { + return Either.right(capabilities.right().value()); + } + toscaNodeType = capabilities.left().value(); + log.debug("Capabilities converted for {}", component.getUniqueId()); + + Either<ToscaNodeType, ToscaError> requirements = capabiltyRequirementConvertor.convertRequirements(component, toscaNodeType); + if (requirements.isRight()) { + return Either.right(requirements.right().value()); + } + toscaNodeType = requirements.left().value(); + log.debug("Requirements converted for {}", component.getUniqueId()); + + String toscaResourceName = ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition()).getToscaResourceName(); + node_types.put(toscaResourceName, toscaNodeType); + toscaNode.setNode_types(node_types); + log.debug("finish convert node type for {}", component.getUniqueId()); + return Either.left(toscaNode); + } + + private Either<Map<String, ToscaNodeTemplate>, ToscaError> convertNodeTemplates(Component component, List<ComponentInstance> componentInstances, Map<String, List<ComponentInstanceProperty>> componentInstancesProperties, + Map<String, Component> componentCache, Map<String, DataTypeDefinition> dataTypes) { + log.debug("start convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType()); + Map<String, ToscaNodeTemplate> node_templates = new HashMap<>(); + + for (ComponentInstance componentInstance : componentInstances) { + ToscaNodeTemplate nodeTemplate = new ToscaNodeTemplate(); + nodeTemplate.setType(componentInstance.getToscaComponentName()); + + Either<ToscaNodeTemplate, ToscaError> requirements = convertComponentInstanceRequirements(component, componentInstance, component.getComponentInstancesRelations(), nodeTemplate); + if (requirements.isRight()) { + return Either.right(requirements.right().value()); + } + log.debug("Component instance Requirements converted for instance {}", componentInstance.getUniqueId()); + + nodeTemplate = requirements.left().value(); + + Component componentOfInstance = componentCache.get(componentInstance.getComponentUid()); + nodeTemplate.setMetadata(convertMetadata(componentOfInstance, true)); + + Either<ToscaNodeTemplate, ToscaError> capabilties = capabiltyRequirementConvertor.convertComponentInstanceCapabilties(componentInstance, dataTypes, nodeTemplate); + if (capabilties.isRight()) { + return Either.right(requirements.right().value()); + } + log.debug("Component instance Capabilties converted for instance {}", componentInstance.getUniqueId()); + + nodeTemplate = capabilties.left().value(); + + if (componentInstancesProperties.containsKey(componentInstance.getUniqueId())) { + Map<String, Object> props = null; + List<ComponentInstanceProperty> propList = componentInstancesProperties.get(componentInstance.getUniqueId()); + List<ComponentInstanceProperty> collect = propList.stream().filter(e -> e.getValueUniqueUid() != null && !e.getValueUniqueUid().isEmpty()).collect(Collectors.toList()); + if (collect != null && !collect.isEmpty()) { + props = new HashMap<String, Object>(); + for (ComponentInstanceProperty prop : collect) { + Object convertedValue = convertInstanceProperty(dataTypes, componentInstance, prop); + props.put(prop.getName(), convertedValue); + } + } + if (props != null && !props.isEmpty()) { + nodeTemplate.setProperties(props); + } + } + node_templates.put(componentInstance.getName(), nodeTemplate); + } + log.debug("finish convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType()); + return Either.left(node_templates); + } + + private Object convertInstanceProperty(Map<String, DataTypeDefinition> dataTypes, ComponentInstance componentInstance, ComponentInstanceProperty prop) { + log.debug("Convert property {} for instance {}", prop.getName(), componentInstance.getUniqueId()); + String propertyType = prop.getType(); + String innerType = null; + if (prop.getSchema() != null && prop.getSchema().getProperty() != null) { + innerType = prop.getSchema().getProperty().getType(); + } + Object convertedValue = propertyConvertor.convertToToscaObject(propertyType, prop.getValue(), innerType, dataTypes); + return convertedValue; + } + + private ToscaGroupTemplate convertGroup(GroupDefinition group, Component component) { + ToscaGroupTemplate toscaGroup = new ToscaGroupTemplate(); + Map<String, String> members = group.getMembers(); + toscaGroup.setType(group.getType()); + if (members != null) + toscaGroup.setMembers(new ArrayList(members.keySet())); + + boolean isVfModule = group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) ? true : false; + IToscaMetadata toscaMetadata; + if (!isVfModule) { + toscaMetadata = new ToscaMetadata(); + } else { + toscaMetadata = new VfModuleToscaMetadata(); + Map<String, Object> properties = new HashMap<>(); + + for (GroupProperty gp : group.getProperties()) { + if (gp.getName().equals(Constants.IS_BASE)) { + Boolean isBase = Boolean.parseBoolean(gp.getValue()); + String type = isBase ? VF_MODULE_TYPE_BASE : VF_MODULE_TYPE_EXPANSION; + properties.put(VF_MODULE_TYPE_KEY, type); + break; + } + } + properties.put(VF_MODULE_DESC_KEY, group.getDescription()); + boolean isVolume = false; + List<String> artifactsList = group.getArtifacts(); + if (artifactsList != null && !artifactsList.isEmpty()) { + + for (String artifactId : artifactsList) { + Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts(); + Optional<ArtifactDefinition> findFirst = deploymentArtifacts.values().stream().filter(p -> p.getUniqueId().equals(artifactId)).findFirst(); + if (findFirst.isPresent()) { + ArtifactDefinition artifactDefinition = findFirst.get(); + if (artifactDefinition.getArtifactType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType())) { + isVolume = true; + break; + } + } + } + } + properties.put(VOLUME_GROUP_KEY, isVolume); + toscaGroup.setProperties(properties); + } + toscaMetadata.setName(group.getName()); + toscaMetadata.setInvariantUUID(group.getInvariantUUID()); + toscaMetadata.setUUID(group.getGroupUUID()); + toscaMetadata.setVersion(group.getVersion()); + toscaGroup.setMetadata(toscaMetadata); + return toscaGroup; + } + + private ToscaNodeType createNodeType(Component component) { + ToscaNodeType toscaNodeType = new ToscaNodeType(); + if (ToscaUtils.isNodeType(component) && ((Resource) component).getDerivedFrom() != null) { + toscaNodeType.setDerived_from(((Resource) component).getDerivedFrom().get(0)); + } + toscaNodeType.setDescription(component.getDescription()); // or name?? + return toscaNodeType; + } + + private Either<ToscaNodeTemplate, ToscaError> convertComponentInstanceRequirements(Component component, ComponentInstance componentInstance, List<RequirementCapabilityRelDef> relations, ToscaNodeTemplate nodeTypeTemplate) { + + List<ComponentInstance> instancesList = component.getComponentInstances(); + List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>(); + Map<String, List<RequirementDefinition>> reqMap = componentInstance.getRequirements(); + + relations.stream().filter(p -> componentInstance.getUniqueId().equals(p.getFromNode())).forEach(req -> { + ComponentInstance toComponentInstance = instancesList.stream().filter(i -> req.getToNode().equals(i.getUniqueId())).findFirst().orElse(null); + if (toComponentInstance == null) { + log.debug("Faild to create relation between node {} to node {}", componentInstance.getName(), req.getToNode()); + return; + + } + RequirementAndRelationshipPair reqAndRelationshopPair = req.getRelationships().get(0); + ToscaTemplateRequirement toscaRequirement = new ToscaTemplateRequirement(); + toscaRequirement.setRelationship(reqAndRelationshopPair.getRelationship().getType()); + toscaRequirement.setNode(toComponentInstance.getName()); + Optional<RequirementDefinition> findAny = reqMap.values().stream().flatMap(e -> e.stream()).filter(e -> e.getName().equals(reqAndRelationshopPair.getRequirement())).findAny(); + if (findAny.isPresent()) { + RequirementDefinition regDefinition = findAny.get(); + toscaRequirement.setCapability(regDefinition.getCapability()); + } else { + log.debug("Faild to find relation between node {} to node {}", componentInstance.getName(), req.getToNode()); + return; + } + Map<String, ToscaTemplateRequirement> reqmap = new HashMap<String, ToscaTemplateRequirement>(); + reqmap.put(reqAndRelationshopPair.getRequirement(), toscaRequirement); + toscaRequirements.add(reqmap); + + }); + + if (!toscaRequirements.isEmpty()) { + nodeTypeTemplate.setRequirements(toscaRequirements); + } + log.debug("Finish convert Requirements for node type"); + return Either.left(nodeTypeTemplate); + } + + private Either<SubstitutionMapping, ToscaError> convertCapabilities(Component component, SubstitutionMapping substitutionMapping, Map<String, DataTypeDefinition> dataTypes) { + Map<String, ToscaCapability> toscaCapabilities = capabiltyRequirementConvertor.convertCapabilities(component, dataTypes); + if (!toscaCapabilities.isEmpty()) { + substitutionMapping.setCapabilities(toscaCapabilities); + } + log.debug("Finish convert Capabilities for node type"); + + return Either.left(substitutionMapping); + } + + private Either<ToscaNodeType, ToscaError> convertCapabilities(Component component, ToscaNodeType nodeType, Map<String, DataTypeDefinition> dataTypes) { + Map<String, ToscaCapability> toscaCapabilities = capabiltyRequirementConvertor.convertCapabilities(component, dataTypes); + if (!toscaCapabilities.isEmpty()) { + nodeType.setCapabilities(toscaCapabilities); + } + log.debug("Finish convert Capabilities for node type"); + + return Either.left(nodeType); + } + + private static class CustomRepresenter extends Representer { + public CustomRepresenter() { + super(); + // null representer is exceptional and it is stored as an instance + // variable. + this.nullRepresenter = new RepresentNull(); + + } + + @Override + protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { + if (propertyValue == null) { + return null; + } else { + // skip not relevant for Tosca property + if (property.getName().equals("dependencies")) { + return null; + } + NodeTuple defaultNode = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); + + return property.getName().equals("_defaultp_") ? new NodeTuple(representData("default"), defaultNode.getValueNode()) : defaultNode; + } + } + + @Override + protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) { + // remove the bean type from the output yaml (!! ...) + if (!classTags.containsKey(javaBean.getClass())) + addClassTag(javaBean.getClass(), Tag.MAP); + + return super.representJavaBean(properties, javaBean); + } + + private class RepresentNull implements Represent { + public Node representData(Object data) { + // possible values are here http://yaml.org/type/null.html + return representScalar(Tag.NULL, ""); + } + } + } + + private static class UnsortedPropertyUtils extends PropertyUtils { + @Override + protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) throws IntrospectionException { + Collection<Property> fields = getPropertiesMap(type, BeanAccess.FIELD).values(); + Set<Property> result = new LinkedHashSet<Property>(fields); + return result; + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaRepresentation.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaRepresentation.java new file mode 100644 index 0000000000..6b1895b6ec --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaRepresentation.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.util.List; + +import org.apache.commons.lang3.tuple.Triple; +import org.openecomp.sdc.be.model.Component; + +public class ToscaRepresentation { + + private String mainYaml; + private List<Triple<String, String, Component>> dependencies; + + public String getMainYaml() { + return mainYaml; + } + + public void setMainYaml(String mainYaml) { + this.mainYaml = mainYaml; + } + + public List<Triple<String, String, Component>> getDependencies() { + return dependencies; + } + + public void setDependencies(List<Triple<String, String, Component>> dependancies) { + this.dependencies = dependancies; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaUtils.java new file mode 100644 index 0000000000..db03ad2307 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaUtils.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; + +public class ToscaUtils { + + public static boolean isNodeType(Component component) { + ComponentTypeEnum componentType = component.getComponentType(); + if (ComponentTypeEnum.RESOURCE.equals(componentType)) { + ResourceTypeEnum resourceType = ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition()).getResourceType(); + if (ResourceTypeEnum.CP.equals(resourceType) || ResourceTypeEnum.VL.equals(resourceType) || ResourceTypeEnum.VFC.equals(resourceType)) { + return true; + } + } + return false; + } + + public static Map<String, Object> objectToMap(Object objectToConvert, Class clazz) throws IllegalArgumentException, IllegalAccessException { + Map<String, Object> map = new HashMap<>(); + List<Field> fields = new ArrayList<>(); + + fields = getAllFields(fields, clazz); + + for (Field field : fields) { + field.setAccessible(true); + map.put(field.getName(), field.get(objectToConvert)); + } + return map; + } + + public static List<Field> getAllFields(List<Field> fields, Class<?> type) { + fields.addAll(Arrays.asList(type.getDeclaredFields())); + + if (type.getSuperclass() != null) { + fields = getAllFields(fields, type.getSuperclass()); + } + return fields; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/EntrySchema.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/EntrySchema.java new file mode 100644 index 0000000000..0c586c7043 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/EntrySchema.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +public class EntrySchema { + private String type; + private String description; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/IToscaMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/IToscaMetadata.java new file mode 100644 index 0000000000..46f4fd032e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/IToscaMetadata.java @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +public interface IToscaMetadata { + + public void setName(String name); + + public void setInvariantUUID(String invariantUUID); + + public void setUUID(String uUID); + + public void setVersion(String version); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/SubstitutionMapping.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/SubstitutionMapping.java new file mode 100644 index 0000000000..0fd9daef7d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/SubstitutionMapping.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.Map; + +public class SubstitutionMapping { + private String node_type; + + private Map<String, ToscaCapability> capabilities; + private Map<String, ToscaRequirement> requirements; + + public SubstitutionMapping() { + super(); + // TODO Auto-generated constructor stub + } + + public String getNode_type() { + return node_type; + } + + public void setNode_type(String node_type) { + this.node_type = node_type; + } + + public Map<String, ToscaCapability> getCapabilities() { + return capabilities; + } + + public void setCapabilities(Map<String, ToscaCapability> capabilities) { + this.capabilities = capabilities; + } + + public Map<String, ToscaRequirement> getRequirements() { + return requirements; + } + + public void setRequirements(Map<String, ToscaRequirement> requirements) { + this.requirements = requirements; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaCapability.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaCapability.java new file mode 100644 index 0000000000..2688e5e6b3 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaCapability.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +public class ToscaCapability { + + private String type; + private String description; + + private List<Object> occurrences; + + private List<String> valid_source_types; + + private Map<String, ToscaProperty> properties; + + public List<String> getValid_source_types() { + return valid_source_types; + } + + public void setValid_source_types(List<String> valid_source_types) { + this.valid_source_types = valid_source_types; + } + + public ToscaCapability() { + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List<Object> getOccurrences() { + return occurrences; + } + + public void setOccurrences(List<Object> occurrences) { + this.occurrences = occurrences; + } + + public Map<String, ToscaProperty> getProperties() { + return properties; + } + + public void setProperties(Map<String, ToscaProperty> properties) { + this.properties = properties; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaGroupTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaGroupTemplate.java new file mode 100644 index 0000000000..b91cffa5be --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaGroupTemplate.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +public class ToscaGroupTemplate { + private String type; + List<String> members; + private IToscaMetadata metadata; + private Map<String, Object> properties; + + public ToscaGroupTemplate() { + super(); + + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public List<String> getMembers() { + return members; + } + + public void setMembers(List<String> members) { + this.members = members; + } + + public IToscaMetadata getMetadata() { + return metadata; + } + + public void setMetadata(IToscaMetadata metadata) { + this.metadata = metadata; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaMetadata.java new file mode 100644 index 0000000000..38cd002726 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaMetadata.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +public class ToscaMetadata implements IToscaMetadata { + private String invariantUUID; + private String UUID; + private String version; + private String name; + private String description; + private String type; + private String category; + private String subcategory; + private String resourceVendor; + private String resourceVendorRelease; + private Boolean serviceEcompNaming; + private Boolean serviceHoming; + + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + public String getInvariantUUID() { + return invariantUUID; + } + + @Override + public void setInvariantUUID(String invariantUUID) { + this.invariantUUID = invariantUUID; + } + + public String getUUID() { + return UUID; + } + + @Override + public void setUUID(String uUID) { + UUID = uUID; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSubcategory() { + return subcategory; + } + + public void setSubcategory(String subcategory) { + this.subcategory = subcategory; + } + + public String getResourceVendor() { + return resourceVendor; + } + + public void setResourceVendor(String resourceVendor) { + this.resourceVendor = resourceVendor; + } + + public String getResourceVendorRelease() { + return resourceVendorRelease; + } + + public void setResourceVendorRelease(String resourceVendorRelease) { + this.resourceVendorRelease = resourceVendorRelease; + } + + public Boolean isServiceEcompNaming() { + return serviceEcompNaming; + } + + public void setServiceEcompNaming(Boolean serviceEcompNaming) { + this.serviceEcompNaming = serviceEcompNaming; + } + + public Boolean isServiceHoming() { + return serviceHoming; + } + + public void setServiceHoming(Boolean serviceHoming) { + this.serviceHoming = serviceHoming; + } + + public String getVersion() { + return version; + } + + @Override + public void setVersion(String version) { + this.version = version; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java new file mode 100644 index 0000000000..b2d7ef5ab6 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +public class ToscaNodeTemplate { + private String type; + private ToscaMetadata metadata; + private Map<String, Object> properties; + private List<Map<String, ToscaTemplateRequirement>> requirements; + private Map<String, ToscaTemplateCapability> capabilities; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + + public List<Map<String, ToscaTemplateRequirement>> getRequirements() { + return requirements; + } + + public void setRequirements(List<Map<String, ToscaTemplateRequirement>> requirements) { + this.requirements = requirements; + } + + public Map<String, ToscaTemplateCapability> getCapabilities() { + return capabilities; + } + + public void setCapabilities(Map<String, ToscaTemplateCapability> capabilities) { + this.capabilities = capabilities; + } + + public ToscaMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ToscaMetadata metadata) { + this.metadata = metadata; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeType.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeType.java new file mode 100644 index 0000000000..df9070f49c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeType.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +public class ToscaNodeType { + public ToscaNodeType() { + } + + private ToscaMetadata metadata; + private String derived_from; + private String description; + + private Map<String, ToscaProperty> properties; + private Map<String, ToscaCapability> capabilities; + + private List<Map<String, ToscaRequirement>> requirements; + + public Map<String, ToscaProperty> getProperties() { + return properties; + } + + public void setProperties(Map<String, ToscaProperty> properties) { + this.properties = properties; + } + + public Map<String, ToscaCapability> getCapabilities() { + return capabilities; + } + + public void setCapabilities(Map<String, ToscaCapability> capabilities) { + this.capabilities = capabilities; + } + + public List<Map<String, ToscaRequirement>> getRequirements() { + return requirements; + } + + public void setRequirements(List<Map<String, ToscaRequirement>> requirements) { + this.requirements = requirements; + } + + public String getDerived_from() { + return derived_from; + } + + public void setDerived_from(String derived_from) { + this.derived_from = derived_from; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ToscaMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ToscaMetadata metadata) { + this.metadata = metadata; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaProperty.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaProperty.java new file mode 100644 index 0000000000..8b5c60b1d4 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaProperty.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +public class ToscaProperty { + + private String type; + private Object _defaultp_; + private String description; + private Boolean required; + private EntrySchema entry_schema; + private String status; + + public EntrySchema getEntry_schema() { + return entry_schema; + } + + public void setEntry_schema(EntrySchema entry_schema) { + this.entry_schema = entry_schema; + } + + public ToscaProperty() { + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Object getDefaultp() { + return _defaultp_; + } + + public void setDefaultp(Object defaultp) { + this._defaultp_ = defaultp; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getRequired() { + return required; + } + + public void setRequired(Boolean required) { + this.required = required; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java new file mode 100644 index 0000000000..21fdc9f722 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +public class ToscaRequirement extends ToscaTemplateRequirement { + + private List<Object> occurrences; + + public ToscaRequirement() { + } + + public List<Object> getOccurrences() { + return occurrences; + } + + public void setOccurrences(List<Object> occurrences) { + this.occurrences = occurrences; + } + + public Map<String, Object> toMap() throws IllegalArgumentException, IllegalAccessException { + return super.toMap(); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java new file mode 100644 index 0000000000..e80d52167c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.tuple.Triple; +import org.openecomp.sdc.be.model.Component; + +public class ToscaTemplate { + private String tosca_definitions_version; + private ToscaMetadata metadata; + private List<Map<String, Map<String, String>>> imports; + private Map<String, ToscaNodeType> node_types; + private ToscaTopolgyTemplate topology_template; + + private List<Triple<String, String, Component>> dependencies; + + public ToscaTemplate(String tosca_definitions_version) { + this.tosca_definitions_version = tosca_definitions_version; + } + + public Map<String, ToscaNodeType> getNode_types() { + return node_types; + } + + public void setNode_types(Map<String, ToscaNodeType> node_types) { + this.node_types = node_types; + } + + public List<Map<String, Map<String, String>>> getImports() { + return imports; + } + + public void setImports(List<Map<String, Map<String, String>>> imports) { + this.imports = imports; + } + + public String getTosca_definitions_version() { + return tosca_definitions_version; + } + + public void setTosca_definitions_version(String tosca_definitions_version) { + this.tosca_definitions_version = tosca_definitions_version; + } + + public ToscaMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ToscaMetadata metadata) { + this.metadata = metadata; + } + + public ToscaTopolgyTemplate getTopology_template() { + return topology_template; + } + + public void setTopology_template(ToscaTopolgyTemplate topology_template) { + this.topology_template = topology_template; + } + + public List<Triple<String, String, Component>> getDependencies() { + return dependencies; + } + + public void setDependencies(List<Triple<String, String, Component>> dependencies) { + this.dependencies = dependencies; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateCapability.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateCapability.java new file mode 100644 index 0000000000..9adb9edfe1 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateCapability.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.List; +import java.util.Map; + +public class ToscaTemplateCapability { + private List<String> valid_source_types; + private Map<String, Object> properties; + + public List<String> getValid_source_types() { + return valid_source_types; + } + + public void setValid_source_types(List<String> valid_source_types) { + this.valid_source_types = valid_source_types; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java new file mode 100644 index 0000000000..71bae81f9c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class ToscaTemplateRequirement { + private String capability; + private String node; + private String relationship; + + public ToscaTemplateRequirement() { + } + + public String getCapability() { + return capability; + } + + public void setCapability(String capability) { + this.capability = capability; + } + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getRelationship() { + return relationship; + } + + public void setRelationship(String relationship) { + this.relationship = relationship; + } + + public Map<String, Object> toMap() throws IllegalArgumentException, IllegalAccessException { + Map<String, Object> map = new HashMap<>(); + Field[] fields = this.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + map.put(field.getName(), field.get(this)); + } + return map; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java new file mode 100644 index 0000000000..6804bf6968 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.Map; + +public class ToscaTopolgyTemplate { + private Map<String, ToscaProperty> inputs; + private Map<String, ToscaNodeTemplate> node_templates; + private Map<String, ToscaGroupTemplate> groups; + private SubstitutionMapping substitution_mappings; + + public Map<String, ToscaNodeTemplate> getNode_templates() { + return node_templates; + } + + public void setNode_templates(Map<String, ToscaNodeTemplate> node_templates) { + this.node_templates = node_templates; + } + + public Map<String, ToscaGroupTemplate> getGroups() { + return groups; + } + + public void setGroups(Map<String, ToscaGroupTemplate> groups) { + this.groups = groups; + } + + public SubstitutionMapping getSubstitution_mappings() { + return substitution_mappings; + } + + public void setSubstitution_mappings(SubstitutionMapping substitution_mapping) { + this.substitution_mappings = substitution_mapping; + } + + public Map<String, ToscaProperty> getInputs() { + return inputs; + } + + public void setInputs(Map<String, ToscaProperty> inputs) { + this.inputs = inputs; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/VfModuleToscaMetadata.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/VfModuleToscaMetadata.java new file mode 100644 index 0000000000..5f978227ef --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/VfModuleToscaMetadata.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +public class VfModuleToscaMetadata implements IToscaMetadata { + + private String vfModuleModelName; + private String vfModuleModelInvariantUUID; + private String vfModuleModelUUID; + private String vfModuleModelVersion; + + @Override + public void setName(String name) { + vfModuleModelName = name; + } + + @Override + public void setInvariantUUID(String invariantUUID) { + vfModuleModelInvariantUUID = invariantUUID; + } + + @Override + public void setUUID(String uUID) { + vfModuleModelUUID = uUID; + } + + @Override + public void setVersion(String version) { + vfModuleModelVersion = version; + } + + public String getVfModuleModelName() { + return vfModuleModelName; + } + + public String getVfModuleModelInvariantUUID() { + return vfModuleModelInvariantUUID; + } + + public String getVfModuleModelUUID() { + return vfModuleModelUUID; + } + + public String getVfModuleModelVersion() { + return vfModuleModelVersion; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java new file mode 100644 index 0000000000..5cfa4a12da --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.user; + +import java.util.List; + +import javax.servlet.ServletContext; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.FunctionalMenuInfo; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.exception.ResponseFormat; + +import fj.data.Either; + +public interface IUserBusinessLogic { + public Either<User, ActionStatus> getUser(String userId, boolean inTransaction); + + public Either<User, ResponseFormat> createUser(User modifier, User newUser); + + public Either<User, ResponseFormat> updateUserRole(User modifier, String userIdToUpdate, String userRole); + + public Either<List<User>, ResponseFormat> getAllAdminUsers(ServletContext context); + + public Either<List<User>, ResponseFormat> getUsersList(String userId, List<String> roles, String rolesStr); + + public Either<User, ResponseFormat> deActivateUser(User modifier, String userUniuqeIdToDeactive); + + public Either<User, ResponseFormat> authorize(User authUser); + + public Either<FunctionalMenuInfo, ActionStatus> getFunctionalMenu(String userId); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/Role.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/Role.java new file mode 100644 index 0000000000..ab58ea7bf0 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/Role.java @@ -0,0 +1,29 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.user; + +/* + * Warning changing the order of the Enum variables changes the ordianl() function output + * which may result in ecompRole id change + */ +public enum Role { + ADMIN, TESTER, DESIGNER, GOVERNOR, OPS, PRODUCT_MANAGER, PRODUCT_STRATEGIST +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserAdminAction.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserAdminAction.java new file mode 100644 index 0000000000..ffc5e4f947 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserAdminAction.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.user; + +public enum UserAdminAction { + + ADD_USER, UPDATE_USER, DELET_USER + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserAdminValidator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserAdminValidator.java new file mode 100644 index 0000000000..8e736d4c0e --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserAdminValidator.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.user; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class UserAdminValidator { + + private Pattern emailPat; + private Pattern userIdPat; + private Matcher matcher; + + private static UserAdminValidator userAdminValidator = null; + + public static synchronized UserAdminValidator getInstance() { + if (userAdminValidator == null) { + userAdminValidator = new UserAdminValidator(); + } + return userAdminValidator; + } + + private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; + + //private static final String USER_ID_PATTERN = "[mM]{1}[0-9]{5}|[a-zA-Z]{2}[0-9]{4}|[a-zA-Z]{2}[0-9]{4}|[a-zA-Z]{2}[0-9]{3}[a-zA-Z]{1}"; + private static final String USER_ID_PATTERN = "^[\\s\\w_.-]{1,50}$"; + + private UserAdminValidator() { + emailPat = Pattern.compile(EMAIL_PATTERN); + userIdPat = Pattern.compile(USER_ID_PATTERN); + } + + public boolean validateEmail(final String hex) { + matcher = emailPat.matcher(hex); + return matcher.matches(); + } + + public boolean validateUserId(String userId) { + matcher = userIdPat.matcher(userId); + return matcher.matches(); + } + + public boolean validateRole(String role) { + for (Role r : Role.values()) { + if (r.name().equals(role)) { + return true; + } + } + return false; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java new file mode 100644 index 0000000000..8a910fc566 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java @@ -0,0 +1,714 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.user; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; +import javax.servlet.ServletContext; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.openecomp.portalsdk.core.onboarding.ueb.FunctionalMenu; +import org.openecomp.portalsdk.core.onboarding.ueb.UebException; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.be.dao.utils.UserStatusEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.FunctionalMenuInfo; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.common.api.UserRoleEnum; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.kpi.api.ASDCKpiApi; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("userBusinessLogic") +public class UserBusinessLogic implements IUserBusinessLogic { + + private static Logger log = LoggerFactory.getLogger(UserBusinessLogic.class.getName()); + private static UserAdminValidator userAdminValidator = UserAdminValidator.getInstance(); + + @Resource + private IUserAdminOperation userAdminOperation; + @Resource + private ComponentsUtils componentsUtils; + @Autowired + private TitanGenericDao titanDao; + + @Override + public Either<User, ActionStatus> getUser(String userId, boolean inTransaction) { + return userAdminOperation.getUserData(userId, inTransaction); + } + + @Override + public Either<User, ResponseFormat> createUser(User modifier, User newUser) { + + ResponseFormat responseFormat; + String modifierUserId = modifier.getUserId(); + + if (modifierUserId == null) { + modifier.setUserId("UNKNOWN"); + log.debug("createUser method - user header is missing"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> eitherCreator = getUser(modifierUserId, false); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + log.debug("createUser method - user is not listed. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + + modifier = eitherCreator.left().value(); + if (!modifier.getRole().equals(UserRoleEnum.ADMIN.getName())) { + log.debug("createUser method - user is not admin={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + + // verify user not exist + User userFromDb = new User(); + // boolean isUserAlreadyExist = false; + Either<User, ActionStatus> eitherUserInDB = getUser(newUser.getUserId(), false); + if (eitherUserInDB.isRight()) { + ActionStatus status = eitherUserInDB.right().value(); + if (!ActionStatus.USER_NOT_FOUND.equals(status) && !ActionStatus.USER_INACTIVE.equals(status)) { + responseFormat = componentsUtils.getResponseFormat(eitherUserInDB.right().value(), newUser.getUserId()); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + } else {// User exist in DB + userFromDb = eitherUserInDB.left().value(); + // isUserAlreadyExist = true; + if (userFromDb.getStatus() == UserStatusEnum.ACTIVE) { + responseFormat = componentsUtils.getResponseFormatByUserId(ActionStatus.USER_ALREADY_EXIST, newUser.getUserId()); + log.debug("createUser method - user already exist with id: {}", modifier.getUserId(), userFromDb.getUserId()); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + } + + newUser.setStatus(UserStatusEnum.ACTIVE); + + // validate Email + if (newUser.getEmail() != null && !userAdminValidator.validateEmail(newUser.getEmail())) { + log.debug("createUser method - user has invalid email={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_EMAIL_ADDRESS, newUser.getEmail()); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + + // validate Role + if (newUser.getRole() == null || newUser.getRole().length() == 0) { + newUser.setRole(Role.DESIGNER.name()); + } else { + if (!userAdminValidator.validateRole(newUser.getRole())) { + log.debug("createUser method - user has invalid role={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_ROLE, newUser.getRole()); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + } + + // handle last login if user is import + if (newUser.getLastLoginTime() == null) { + newUser.setLastLoginTime(0L); + } + + Either<User, StorageOperationStatus> addOrUpdateUserReq; + + if (ActionStatus.USER_INACTIVE.equals(eitherUserInDB.right().value())) { // user + // exist + // with + // inactive + // state + // - + // update + // user + // data + newUser.setLastLoginTime(0L); + addOrUpdateUserReq = userAdminOperation.updateUserData(newUser); + + } else { // user not exist - create new user + if (newUser.getUserId() != null && !userAdminValidator.validateUserId(newUser.getUserId())) { + log.debug("createUser method - user has invalid userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_USER_ID, newUser.getUserId()); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.ADD_USER); + return Either.right(responseFormat); + } + addOrUpdateUserReq = userAdminOperation.saveUserData(newUser); + } + + if (addOrUpdateUserReq.isRight() || addOrUpdateUserReq.left().value() == null) { + log.debug("createUser method - failed to create user"); + Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(addOrUpdateUserReq.right().value()))); + } + log.debug("createUser method - user created"); + User createdUser = addOrUpdateUserReq.left().value(); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED); + handleAuditing(modifier, null, createdUser, responseFormat, AuditingActionEnum.ADD_USER); + return Either.left(createdUser); + } + + @Override + public Either<User, ResponseFormat> updateUserRole(User modifier, String userIdToUpdate, String userRole) { + + ResponseFormat responseFormat; + String modifierUserId = modifier.getUserId(); + + if (modifierUserId == null) { + modifier.setUserId("UNKNOWN"); + log.debug("updateUserRole method - user header is missing"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> eitherCreator = getUser(modifierUserId, false); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + log.debug("updateUserRole method - user is not listed. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + + modifier = eitherCreator.left().value(); + if (!modifier.getRole().equals(UserRoleEnum.ADMIN.getName())) { + log.debug("updateUserRole method - user is not admin. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + + if (modifier.getUserId().equals(userIdToUpdate)) { + log.debug("updateUserRole method - admin role can only be updated by other admin. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.UPDATE_USER_ADMIN_CONFLICT); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> userToUpdateReq = getUser(userIdToUpdate, false); + if (userToUpdateReq.isRight() || userToUpdateReq.left().value() == null) { + log.debug("updateUserRole method - user not found. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.USER_NOT_FOUND, userIdToUpdate); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + + if (!userAdminValidator.validateRole(userRole)) { + log.debug("updateUserRole method - user has invalid role={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_ROLE, userRole); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + + User newUser = new User(); + newUser.setRole(userRole); + newUser.setUserId(userIdToUpdate); + User userToUpdate = userToUpdateReq.left().value(); + // if(!userRole.equals(UserRoleEnum.ADMIN.getName())){ //this is in + // comment until admin will be able to do do check-in/check-out from the + // UI + + Either<List<Edge>, StorageOperationStatus> userPendingTasksReq = getPandingUserPandingTasksWithCommit(userToUpdate); + if (userPendingTasksReq.isRight()) { + log.debug("updateUserRole method - failed to get user pending tasks list", userIdToUpdate); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(userPendingTasksReq.right().value()))); + } + + List<Edge> userPendingTasks = userPendingTasksReq.left().value(); + if (userPendingTasks.size() > 0) { + log.debug("updateUserRole method - User canot be updated, user have panding projects", userIdToUpdate); + String userTasksStatusForErrorMessage = getUserPandingTaskStatusByRole(UserRoleEnum.valueOf(userToUpdate.getRole())); + String userInfo = userToUpdate.getFirstName() + " " + userToUpdate.getLastName() + '(' + userToUpdate.getUserId() + ')'; + responseFormat = componentsUtils.getResponseFormat(ActionStatus.CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS, userInfo, userTasksStatusForErrorMessage); + handleAuditing(modifier, userToUpdate, userToUpdate, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.right(responseFormat); + } + // } + Either<User, StorageOperationStatus> updateUserReq = userAdminOperation.updateUserData(newUser); + + if (updateUserReq.isRight() || updateUserReq.left().value() == null) { + log.debug("updateUser method - failed to update user data. userId={}", modifier.getUserId()); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateUserReq.right().value()))); + } + + responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + User updatedUser = updateUserReq.left().value(); + handleAuditing(modifier, userToUpdate, updatedUser, responseFormat, AuditingActionEnum.UPDATE_USER); + return Either.left(updatedUser); + } + + @Override + public Either<List<User>, ResponseFormat> getAllAdminUsers(ServletContext context) { + Either<List<User>, ActionStatus> response = userAdminOperation.getAllUsersWithRole(Role.ADMIN.name(), null); + + if (response.isRight()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormat(response.right().value()); + return Either.right(responseFormat); + } + return Either.left(response.left().value()); + } + + @Override + public Either<List<User>, ResponseFormat> getUsersList(String modifierAttId, List<String> roles, String rolesStr) { + ResponseFormat responseFormat; + User user = new User(); + if (modifierAttId == null) { + user.setUserId("UNKNOWN"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + handleGetUsersListAuditing(user, responseFormat, rolesStr); + return Either.right(responseFormat); + } + Either<User, ActionStatus> userResult = getUser(modifierAttId, false); + if (userResult.isRight()) { + user.setUserId(modifierAttId); + if (userResult.right().value().equals(ActionStatus.USER_NOT_FOUND)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + } else { + responseFormat = componentsUtils.getResponseFormat(userResult.right().value()); + } + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeUserMissingError, "Get users per roles", modifierAttId); + BeEcompErrorManager.getInstance().logBeUserMissingError("Get users per roles", modifierAttId); + + handleGetUsersListAuditing(user, responseFormat, rolesStr); + return Either.right(responseFormat); + } + user = userResult.left().value(); + Either<List<User>, ResponseFormat> getResponse = null; + List<User> resultList = new ArrayList<>(); + if (roles != null && !roles.isEmpty()) { + for (String role : roles) { + if (!userAdminValidator.validateRole(role)) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_ROLE, role); + handleGetUsersListAuditing(user, responseFormat, rolesStr); + return Either.right(responseFormat); + } + getResponse = getUsersPerRole(role, user, rolesStr); + resultList.addAll(getResponse.left().value()); + } + } else { + rolesStr = "All"; + getResponse = getUsersPerRole(null, user, rolesStr); + resultList.addAll(getResponse.left().value()); + } + responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleGetUsersListAuditing(user, responseFormat, rolesStr); + return Either.left(resultList); + } + + private Either<List<User>, ResponseFormat> getUsersPerRole(String role, User user, String rolesStr) { + ResponseFormat responseFormat; + Either<List<User>, ActionStatus> response = userAdminOperation.getAllUsersWithRole(role, UserStatusEnum.ACTIVE.name()); + if (response.isRight()) { + responseFormat = componentsUtils.getResponseFormat(response.right().value()); + handleGetUsersListAuditing(user, responseFormat, rolesStr); + return Either.right(responseFormat); + } + return Either.left(response.left().value()); + } + + private void handleGetUsersListAuditing(User user, ResponseFormat responseFormat, String details) { + componentsUtils.auditGetUsersList(AuditingActionEnum.GET_USERS_LIST, user, details, responseFormat); + } + + private void handleAuditing(User modifier, User userBefor, User userAfter, ResponseFormat responseFormat, AuditingActionEnum actionName) { + componentsUtils.auditAdminUserAction(actionName, modifier, userBefor, userAfter, responseFormat); + } + + private void handleUserAccessAuditing(User user, ResponseFormat responseFormat, AuditingActionEnum actionName) { + componentsUtils.auditUserAccess(actionName, user, responseFormat); + } + + @Override + public Either<User, ResponseFormat> deActivateUser(User modifier, String userUniuqeIdToDeactive) { + + ResponseFormat responseFormat; + String userId = modifier.getUserId(); + + if (userId == null) { + modifier.setUserId("UNKNOWN"); + log.debug("deActivateUser method - user header is missing"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> eitherCreator = getUser(userId, false); + if (eitherCreator.isRight() || eitherCreator.left().value() == null) { + log.debug("deActivateUser method - user is not listed. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(responseFormat); + } + + modifier = eitherCreator.left().value(); + + if (!modifier.getRole().equals(UserRoleEnum.ADMIN.getName())) { + log.debug("deActivateUser method - user is not admin. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(responseFormat); + } + + if (modifier.getUserId().equals(userUniuqeIdToDeactive)) { + log.debug("deActivateUser deActivateUser - admin can only be deactivate by other admin. userId={}", modifier.getUserId()); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.DELETE_USER_ADMIN_CONFLICT); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> getUserToDeleteResponse = getUser(userUniuqeIdToDeactive, false); + if (getUserToDeleteResponse.isRight() || getUserToDeleteResponse.left().value() == null) { + log.debug("deActivateUser method - failed to get user by id {}", userUniuqeIdToDeactive); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.USER_NOT_FOUND, userUniuqeIdToDeactive); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(componentsUtils.getResponseFormat(getUserToDeleteResponse.right().value(), userUniuqeIdToDeactive)); + } + + User userToDeactivate = getUserToDeleteResponse.left().value(); + if (userToDeactivate.getStatus().equals(UserStatusEnum.INACTIVE)) { + log.debug("deActivateUser method - User already inactive", userUniuqeIdToDeactive); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.USER_NOT_FOUND, userUniuqeIdToDeactive); + handleAuditing(modifier, null, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(responseFormat); + } + + Either<List<Edge>, StorageOperationStatus> userPendingTasksReq = getPandingUserPandingTasksWithCommit(userToDeactivate); + if (userPendingTasksReq.isRight()) { + log.debug("deActivateUser method - failed to get user pending tasks list", userUniuqeIdToDeactive); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(userPendingTasksReq.right().value()))); + } + + List<Edge> userPendingTasks = userPendingTasksReq.left().value(); + if (userPendingTasks.size() > 0) { + log.debug("deActivateUser method - User canot be deleted, user have panding projects", userUniuqeIdToDeactive); + + String userTasksStatusForErrorMessage = getUserPandingTaskStatusByRole(UserRoleEnum.valueOf(userToDeactivate.getRole())); + String userInfo = userToDeactivate.getFirstName() + " " + userToDeactivate.getLastName() + '(' + userToDeactivate.getUserId() + ')'; + responseFormat = componentsUtils.getResponseFormat(ActionStatus.CANNOT_DELETE_USER_WITH_ACTIVE_ELEMENTS, userInfo, userTasksStatusForErrorMessage); + handleAuditing(modifier, userToDeactivate, userToDeactivate, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.right(responseFormat); + } + + Either<User, StorageOperationStatus> deactivateUserReq = userAdminOperation.deActivateUser(userToDeactivate); + if (deactivateUserReq.isRight()) { + log.debug("deActivateUser method - failed to deactivate user", userUniuqeIdToDeactive); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deactivateUserReq.right().value()))); + } + User deactivateUser = deactivateUserReq.left().value(); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleAuditing(modifier, userToDeactivate, null, responseFormat, AuditingActionEnum.DELETE_USER); + return Either.left(deactivateUser); + } + + @Override + public Either<User, ResponseFormat> authorize(User authUser) { + + ResponseFormat responseFormat; + + String userId = authUser.getUserId(); + + if (userId == null) { + authUser.setUserId("UNKNOWN"); + log.debug("deActivateUser method - user header is missing"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + handleUserAccessAuditing(authUser, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> eitherCreator = getUser(userId, false); + if (eitherCreator.isRight()) { + if (eitherCreator.right().value() == ActionStatus.USER_NOT_FOUND || eitherCreator.right().value() == ActionStatus.USER_INACTIVE) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_ACCESS); + handleUserAccessAuditing(authUser, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.right(responseFormat); + } else { + return Either.right(componentsUtils.getResponseFormatByUser(eitherCreator.right().value(), authUser)); + } + } else { + if (eitherCreator.left().value() == null) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + return Either.right(responseFormat); + } + } + + User user = eitherCreator.left().value(); + + String firstName = authUser.getFirstName(); + if (firstName != null && firstName.isEmpty() == false && !firstName.equals(user.getFirstName())) { + user.setFirstName(firstName); + } + + String lastName = authUser.getLastName(); + if (lastName != null && lastName.isEmpty() == false && !lastName.equals(user.getLastName())) { + user.setLastName(lastName); + } + + String email = authUser.getEmail(); + if (email != null && false == email.isEmpty() && !email.equals(user.getEmail())) { + user.setEmail(email); + } + + // last login time stamp handle + user.setLastLoginTime(); + + Either<User, StorageOperationStatus> updateUserReq = userAdminOperation.updateUserData(user); + + if (updateUserReq.isRight()) { + responseFormat = componentsUtils.getResponseFormatByUser(eitherCreator.right().value(), user); + handleUserAccessAuditing(user, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.right(componentsUtils.getResponseFormatByUser(eitherCreator.right().value(), user)); + } + + User updatedUser = updateUserReq.left().value(); + + Long lastLoginTime = user.getLastLoginTime(); + if (lastLoginTime != null) { + updatedUser.setLastLoginTime(lastLoginTime); + } else { + updatedUser.setLastLoginTime(new Long(0)); + } + + responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleUserAccessAuditing(updatedUser, responseFormat, AuditingActionEnum.USER_ACCESS); + ASDCKpiApi.countUsersAuthorizations(); + return Either.left(updatedUser); + } + + /* + * The method updates user credentials only, the role is neglected The role updated through updateRole method + */ + public Either<User, ResponseFormat> updateUserCredentials(User updatedUserCred) { + + ResponseFormat responseFormat; + + String userId = updatedUserCred.getUserId(); + + if (userId == null) { + updatedUserCred.setUserId("UNKNOWN"); + log.debug("updateUserCredentials method - user header is missing"); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); + handleUserAccessAuditing(updatedUserCred, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.right(responseFormat); + } + + Either<User, ActionStatus> eitherCreator = getUser(userId, false); + if (eitherCreator.isRight()) { + ActionStatus status = eitherCreator.right().value(); + if (status == ActionStatus.USER_NOT_FOUND || status == ActionStatus.USER_INACTIVE) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_ACCESS); + handleUserAccessAuditing(updatedUserCred, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.right(responseFormat); + } else { + return Either.right(componentsUtils.getResponseFormatByUser(status, updatedUserCred)); + } + } else { + if (eitherCreator.left().value() == null) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + return Either.right(responseFormat); + } + } + + User user = eitherCreator.left().value(); + + String firstName = updatedUserCred.getFirstName(); + if (firstName != null && firstName.isEmpty() == false && !firstName.equals(user.getFirstName())) { + user.setFirstName(firstName); + } + + String lastName = updatedUserCred.getLastName(); + if (lastName != null && lastName.isEmpty() == false && !lastName.equals(user.getLastName())) { + user.setLastName(lastName); + } + + String email = updatedUserCred.getEmail(); + if (email != null && false == email.isEmpty() && !email.equals(user.getEmail())) { + user.setEmail(email); + } + + if (updatedUserCred.getLastLoginTime() != null && user.getLastLoginTime() != null) { + if (updatedUserCred.getLastLoginTime() > user.getLastLoginTime()) { + user.setLastLoginTime(updatedUserCred.getLastLoginTime()); + } + } else if (updatedUserCred.getLastLoginTime() != null && user.getLastLoginTime() == null) { + user.setLastLoginTime(updatedUserCred.getLastLoginTime()); + } + + Either<User, StorageOperationStatus> updateUserReq = userAdminOperation.updateUserData(user); + + if (updateUserReq.isRight()) { + responseFormat = componentsUtils.getResponseFormatByUser(eitherCreator.right().value(), user); + handleUserAccessAuditing(user, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.right(componentsUtils.getResponseFormatByUser(eitherCreator.right().value(), user)); + } + + User updatedUser = updateUserReq.left().value(); + + responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK); + handleUserAccessAuditing(updatedUser, responseFormat, AuditingActionEnum.USER_ACCESS); + return Either.left(updatedUser); + } + + private Either<List<Edge>, StorageOperationStatus> getPandingUserPandingTasksWithCommit(User user) { + + Either<List<Edge>, StorageOperationStatus> result = null; + + try { + UserRoleEnum userRole = UserRoleEnum.valueOf(user.getRole()); + Map<String, Object> properties = new HashMap<String, Object>(); + switch (userRole) { + case DESIGNER: + case PRODUCT_STRATEGIST: + case PRODUCT_MANAGER: + properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + return userAdminOperation.getUserPandingTasksList(user, properties); + case TESTER: + properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + return userAdminOperation.getUserPandingTasksList(user, properties); + case ADMIN: + properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + return userAdminOperation.getUserPandingTasksList(user, properties); + default: + return Either.left(new ArrayList<>()); + } + } finally { + // commit will be perform outside!!! + if (result == null || result.isRight()) { + log.debug("getUserPandingTasksList failed to perform fetching"); + titanDao.rollback(); + } else { + titanDao.commit(); + } + } + } + + private String getUserPandingTaskStatusByRole(UserRoleEnum role) { + + switch (role) { + case DESIGNER: + case PRODUCT_STRATEGIST: + case PRODUCT_MANAGER: + return "checked-out"; + + case TESTER: + return "in-certification"; + case ADMIN: + return "in-certification/checked-out"; + default: + return ""; + } + } + + /** + * return the functional menu of a given user + * + * @param userId + * @param inTransaction + * @return + */ + public Either<FunctionalMenuInfo, ActionStatus> getFunctionalMenu(String userId) { + + boolean toCommit = false; + + FunctionalMenuInfo functionalMenuInfo = new FunctionalMenuInfo(); + + try { + + Either<ImmutablePair<User, FunctionalMenuInfo>, ActionStatus> userResult = userAdminOperation.getUserDataWithFunctionalMenu(userId); + if (userResult.isRight()) { + ActionStatus actionStatus = userResult.right().value(); + if (actionStatus == ActionStatus.USER_NOT_FOUND) { + actionStatus = ActionStatus.INVALID_USER_ID; + } + return Either.right(actionStatus); + } + + ImmutablePair<User, FunctionalMenuInfo> immutablePair = userResult.left().value(); + FunctionalMenuInfo currentFunctionalMenu = immutablePair.right; + String currentMenuStr = currentFunctionalMenu != null ? currentFunctionalMenu.getFunctionalMenu() : null; + + String functionalMenu = getFunctionalMenuFromUeb(userId); + + // functionalMenu can be null or since we catch UebException + if (functionalMenu != null && false == functionalMenu.isEmpty()) { + functionalMenuInfo.setFunctionalMenu(functionalMenu); + if (false == functionalMenu.equals(currentMenuStr)) { + log.debug("Going to update functional menu of user {}. Functional menu is {}", userId, functionalMenu); + userAdminOperation.createOrUpdateFunctionalMenu(userId, functionalMenu); + } + } else { + String menu = currentMenuStr; + if (menu == null) { + menu = "[]"; + } + log.debug("Fetch functional menu from old request. Functional menu is {}", menu); + functionalMenuInfo.setFunctionalMenu(menu); + } + + toCommit = true; + + } finally { + if (toCommit) { + titanDao.commit(); + } else { + titanDao.rollback(); + } + } + + return Either.left(functionalMenuInfo); + } + + private String getFunctionalMenuFromUeb(String userId) { + String functionalMenu = null; + try { + log.debug("Before calling to FunctionalMenu method for user {}", userId); + functionalMenu = FunctionalMenu.get(userId); + log.debug("Functional menu fetched is {}", functionalMenu); + + } catch (UebException e) { + log.debug("Failed to fetch 'functional menu' of user {} from ecomp portal(via UEB). {}", userId, e); + BeEcompErrorManager.getInstance().logInternalFlowError("FetchFunctionalMenu", "Failed to fetch 'functional menu'", ErrorSeverity.ERROR); + } + return functionalMenu; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/ICommitHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/ICommitHandler.java new file mode 100644 index 0000000000..e70b33a938 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/ICommitHandler.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.api; + +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; + +public interface ICommitHandler extends IDBType { + DBActionCodeEnum doCommit(); +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/IDBAction.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/IDBAction.java new file mode 100644 index 0000000000..a36e5fe1b5 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/IDBAction.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.api; + +public interface IDBAction { + <T> T doAction(); +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/IDBType.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/IDBType.java new file mode 100644 index 0000000000..4c19e41609 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/IDBType.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.api; + +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; + +public interface IDBType { + DBTypeEnum getDBType(); +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/ITransactionSdnc.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/ITransactionSdnc.java new file mode 100644 index 0000000000..5a10e9029c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/ITransactionSdnc.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.api; + +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.ESActionTypeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.TransactionCodeEnum; + +import fj.data.Either; + +public interface ITransactionSdnc { + TransactionCodeEnum finishTransaction(); + + Either<DBActionCodeEnum, TransactionCodeEnum> invokeESAction(boolean isLastAction, ESActionTypeEnum esActiontype, ESArtifactData artifactData); + + <T> Either<T, TransactionCodeEnum> invokeGeneralDBAction(boolean isLastAction, DBTypeEnum dbType, IDBAction dbAction, IDBAction dbRollbackAction); + + <T> Either<T, TransactionCodeEnum> invokeTitanAction(boolean isLastAction, IDBAction dbAction); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/RollbackHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/RollbackHandler.java new file mode 100644 index 0000000000..97a8083e88 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/RollbackHandler.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.api; + +import java.util.Stack; + +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.LogMessages; +import org.openecomp.sdc.common.util.MethodActivationStatusEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class RollbackHandler implements IDBType { + private static Logger log = LoggerFactory.getLogger(RollbackHandler.class.getName()); + private Stack<IDBAction> dbActionRollbacks; + + private Integer transactionId; + private String userId, actionType; + + protected RollbackHandler(Integer transactionId, String userId, String actionType) { + if (isRollbackForPersistenceData()) { + dbActionRollbacks = new Stack<>(); + } + this.transactionId = transactionId; + this.userId = userId; + this.actionType = actionType; + } + + public MethodActivationStatusEnum addRollbackAction(IDBAction rollbackAction) { + MethodActivationStatusEnum result = MethodActivationStatusEnum.SUCCESS; + if (isRollbackForPersistenceData()) { + dbActionRollbacks.push(rollbackAction); + } else { + result = MethodActivationStatusEnum.NOT_ALLOWED; + } + return result; + } + + public DBActionCodeEnum doRollback() { + DBActionCodeEnum result; + + try { + if (isRollbackForPersistenceData()) { + result = doPersistenceDataRollback(); + } else { + log.debug(LogMessages.ROLLBACK_NON_PERSISTENT_ACTION, getDBType().name(), transactionId, userId, actionType); + log.debug(TransactionUtils.TRANSACTION_MARKER, LogMessages.ROLLBACK_NON_PERSISTENT_ACTION, getDBType().name(), transactionId, userId, actionType); + result = doNonPersistenceDataRollback(); + } + if (result != DBActionCodeEnum.SUCCESS) { + log.error(LogMessages.ROLLBACK_FAILED_ON_DB, transactionId, getDBType().name(), userId, actionType); + log.error(TransactionUtils.TRANSACTION_MARKER, LogMessages.ROLLBACK_FAILED_ON_DB, transactionId, getDBType().name(), userId, actionType); + } + + } catch (Exception e) { + result = DBActionCodeEnum.FAIL_GENERAL; + log.error(LogMessages.ROLLBACK_FAILED_ON_DB_WITH_EXCEPTION, transactionId, getDBType().name(), e.getMessage(), userId, actionType); + log.debug(LogMessages.ROLLBACK_FAILED_ON_DB_WITH_EXCEPTION, transactionId, getDBType().name(), e.getMessage(), userId, actionType, e); + log.error(TransactionUtils.TRANSACTION_MARKER, LogMessages.ROLLBACK_FAILED_ON_DB_WITH_EXCEPTION, transactionId, getDBType().name(), e.getMessage(), userId, actionType); + } + + return result; + } + + private <T> DBActionCodeEnum doPersistenceDataRollback() { + DBActionCodeEnum result = DBActionCodeEnum.SUCCESS; + while (!dbActionRollbacks.empty()) { + log.debug(LogMessages.ROLLBACK_PERSISTENT_ACTION, getDBType().name(), transactionId, userId, actionType); + log.debug(TransactionUtils.TRANSACTION_MARKER, LogMessages.ROLLBACK_PERSISTENT_ACTION, getDBType().name(), transactionId, userId, actionType); + IDBAction rollbackAction = dbActionRollbacks.pop(); + T rollbackResult = rollbackAction.doAction(); + if (!isRollbackResultValid(rollbackResult)) { + result = DBActionCodeEnum.FAIL_GENERAL; + } + } + return result; + } + + /** + * Override for specific logic + * + * @param <T> + */ + public <T> boolean isRollbackResultValid(T rollbackResult) { + return true; + } + + /** + * Override for specific logic + */ + public DBActionCodeEnum doNonPersistenceDataRollback() { + return DBActionCodeEnum.SUCCESS; + } + + protected abstract boolean isRollbackForPersistenceData(); + + /** + * Only Used for Unit Tests ! + */ + public static void setLog(Logger log) { + RollbackHandler.log = log; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/TransactionUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/TransactionUtils.java new file mode 100644 index 0000000000..e90b9618d4 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/api/TransactionUtils.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.api; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +public final class TransactionUtils { + + private TransactionUtils() { + + } + + public enum DBTypeEnum { + ELASTIC_SEARCH, TITAN, MYSTERY, SWIFT + } + + public enum TransactionCodeEnum { + ROLLBACK_SUCCESS, ROLLBACK_FAILED, SUCCESS, COMMIT_FAILED, MULTIPLE_LAST_ACTION, INTERNAL_ERROR, UNALLOWED_METHOD_USAGE, PREPARE_ROLLBACK_FAILED, TRANSACTION_CLOSED + } + + public enum TransactionStatusEnum { + OPEN, CLOSED, FAILED_ROLLBACK + } + + public enum DBActionCodeEnum { + SUCCESS, FAIL_GENERAL, FAIL_MULTIPLE_LAST_ACTION + } + + public enum ESActionTypeEnum { + ADD_ARTIFACT, UPDATE_ARTIFACT, REMOVE_ARTIFACT + } + + public enum ActionTypeEnum { + ADD_ARTIFACT, REMOVE_ARTIFACT, UPDATE_ARTIFACT, CREATE_RESOURCE, UPDATE_RESOURCE, DELETE_RESOURCE + } + + public static final int MAX_SIZE_TRANSACTION_LIST = 1000; + + public static final int TRANSACTION_ID_RESET_LIMIT = MAX_SIZE_TRANSACTION_LIST * 10; + + public static final String TRANSACTION_MARKER_STR = "TRANSACTION_MARKER"; + + public static final String DUMMY_USER = "udummy"; + + public static final Marker TRANSACTION_MARKER = MarkerFactory.getMarker(TRANSACTION_MARKER_STR); + + public static class LogMessages { + public static final String PRE_INVOKE_ACTION = "About to add Action to SdncTransaction ID:{} for DB:{}, user:{}, action:{}"; + public static final String INVOKE_ACTION = "invoking Action in SdncTransactionID:{}, on DB:{}, user:{}, action:{}"; + public static final String COMMIT_ACTION_ALL_DB = "Starting Commit for SdncTransactionID:{} for all DBs, user:{}, action:{}"; + public static final String COMMIT_ACTION_SPECIFIC_DB = "Starting Commit for SdncTransactionID:{} on DB:{}, user:{}, action:{}"; + public static final String COMMIT_ON_CLOSED_TRANSACTION = "Commit failed for SdncTransactionID:{} Transaction is in status:{}, user:{}, action:{}"; + public static final String ACTION_ON_CLOSED_TRANSACTION = "Action failed for SdncTransactionID:{} Transaction is already closed, user:{}, action:{}"; + public static final String DOUBLE_FINISH_FLAG_ACTION = "Transaction with SdncTransactionID:{} on DB:{} was called multiple times with last action flag, user:{}, action:{}"; + public static final String DB_ACTION_FAILED_WITH_EXCEPTION = "Action on DB:{} has failed for SdncTransactionID:{}, message:{}, user:{}, action:{}"; + public static final String ROLLBACK_SUCCEEDED_GENERAL = "Transaction rollback succeeded for SdncTransactionID:{}, user:{}, action:{}"; + public static final String ROLLBACK_FAILED_GENERAL = "Transaction rollback failed for SdncTransactionID:{}, user:{}, action:{}"; + public static final String ROLLBACK_FAILED_ON_DB = "Transaction rollback failed for SdncTransactionID:{} on DB:{}, user:{}, action:{}"; + public static final String ROLLBACK_FAILED_ON_DB_WITH_EXCEPTION = "Transaction rollback failed for SdncTransactionID:{} on DB:{}, exception message:{}, user:{}, action:{}"; + public static final String ROLLBACK_PERSISTENT_ACTION = "About To Rollback Action on DB{} for TransactionID:{} ... user:{}, action:{}"; + public static final String ROLLBACK_NON_PERSISTENT_ACTION = "About To Rollback Actions on DB{} for TransactionID:{} ... user:{}, action:{}"; + public static final String CREATE_ROLLBACK_HANDLER = "creating new Rollback Handler For DB:{} in SdncTransaction ID:{}, user:{}, action:{}"; + public static final String FAILED_CREATE_ROLLBACK = "failed to create new Rollback action For DB:{} with SdncTransactionID:{}, user:{}, action:{}"; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/ESAction.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/ESAction.java new file mode 100644 index 0000000000..33a8d1163b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/ESAction.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.impl; + +import org.openecomp.sdc.be.dao.impl.ESCatalogDAO; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.be.resources.exception.ResourceDAOException; +import org.openecomp.sdc.common.transaction.api.IDBAction; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.ESActionTypeEnum; + +public class ESAction implements IDBAction { + + private ESCatalogDAO esCatalogDao; + private ESArtifactData artifactData; + private ESActionTypeEnum esActionType; + + public ESAction(ESCatalogDAO esCatalogDao, ESArtifactData artifactData, ESActionTypeEnum esActiontype) { + this.esCatalogDao = esCatalogDao; + this.artifactData = artifactData; + this.esActionType = esActiontype; + } + + @Override + public DBActionCodeEnum doAction() { + DBActionCodeEnum result = DBActionCodeEnum.SUCCESS; + try { + if (esActionType == ESActionTypeEnum.ADD_ARTIFACT || esActionType == ESActionTypeEnum.UPDATE_ARTIFACT) { + esCatalogDao.writeArtifact(artifactData); + } else if (esActionType == ESActionTypeEnum.REMOVE_ARTIFACT) { + esCatalogDao.deleteArtifact(artifactData.getId()); + } + + } catch (ResourceDAOException daoException) { + result = DBActionCodeEnum.FAIL_GENERAL; + } + return result; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/ESRollbackHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/ESRollbackHandler.java new file mode 100644 index 0000000000..b9fb0d31b7 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/ESRollbackHandler.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.impl; + +import org.openecomp.sdc.be.dao.api.ResourceUploadStatus; +import org.openecomp.sdc.be.dao.impl.ESCatalogDAO; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.common.transaction.api.RollbackHandler; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.ESActionTypeEnum; +import org.openecomp.sdc.common.util.MethodActivationStatusEnum; + +import fj.data.Either; + +public class ESRollbackHandler extends RollbackHandler { + + public ESRollbackHandler(Integer transactionId, String userId, String actionType) { + super(transactionId, userId, actionType); + } + + public DBTypeEnum getDBType() { + return DBTypeEnum.ELASTIC_SEARCH; + } + + protected boolean isRollbackForPersistenceData() { + return true; + } + + public boolean isRollbackResultValid(DBActionCodeEnum rollbackResult) { + return rollbackResult == DBActionCodeEnum.SUCCESS; + } + + public Either<ESAction, MethodActivationStatusEnum> buildEsRollbackAction(ESCatalogDAO esCatalogDao, ESArtifactData artifactData, ESActionTypeEnum esActiontype) { + Either<ESAction, MethodActivationStatusEnum> result; + + try { + ESAction esRollbackAction = null; + Either<ESArtifactData, ResourceUploadStatus> either = esCatalogDao.getArtifact(artifactData.getId()); + + switch (esActiontype) { + case ADD_ARTIFACT: + + if (either.isRight() && either.right().value() == ResourceUploadStatus.NOT_EXIST) { + esRollbackAction = new ESAction(esCatalogDao, artifactData, ESActionTypeEnum.REMOVE_ARTIFACT); + } + break; + case REMOVE_ARTIFACT: + if (either.isLeft()) { + esRollbackAction = new ESAction(esCatalogDao, artifactData, ESActionTypeEnum.ADD_ARTIFACT); + } + break; + case UPDATE_ARTIFACT: + + if (either.isLeft()) { + ESArtifactData originalArtifactData = either.left().value(); + esRollbackAction = new ESAction(esCatalogDao, originalArtifactData, ESActionTypeEnum.UPDATE_ARTIFACT); + } + break; + + } + if (esRollbackAction != null) { + result = Either.left(esRollbackAction); + } else { + result = Either.right(MethodActivationStatusEnum.FAILED); + } + } catch (Exception e) { + result = Either.right(MethodActivationStatusEnum.FAILED); + } + + return result; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/TitanCommitHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/TitanCommitHandler.java new file mode 100644 index 0000000000..0d2ec387cf --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/TitanCommitHandler.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.impl; + +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.common.transaction.api.ICommitHandler; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; + +public class TitanCommitHandler implements ICommitHandler { + + private TitanGenericDao titanGenericDao; + + public TitanCommitHandler(TitanGenericDao titanGenericDao) { + this.titanGenericDao = titanGenericDao; + } + + @Override + public DBActionCodeEnum doCommit() { + DBActionCodeEnum result = DBActionCodeEnum.SUCCESS; + TitanOperationStatus titanStatus = titanGenericDao.commit(); + if (titanStatus != TitanOperationStatus.OK) { + result = DBActionCodeEnum.FAIL_GENERAL; + } + return result; + } + + @Override + public DBTypeEnum getDBType() { + return DBTypeEnum.TITAN; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/TitanRollbackHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/TitanRollbackHandler.java new file mode 100644 index 0000000000..c0c686723c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/impl/TitanRollbackHandler.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.impl; + +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.common.transaction.api.RollbackHandler; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; + +public class TitanRollbackHandler extends RollbackHandler { + + private TitanGenericDao titanGenericDao; + + public TitanRollbackHandler(Integer transactionId, String userId, String actionType, TitanGenericDao titanGenericDao) { + super(transactionId, userId, actionType); + this.titanGenericDao = titanGenericDao; + } + + public DBTypeEnum getDBType() { + return DBTypeEnum.TITAN; + } + + protected boolean isRollbackForPersistenceData() { + return false; + } + + public DBActionCodeEnum doNonPersistenceDataRollback() { + DBActionCodeEnum result = DBActionCodeEnum.SUCCESS; + TitanOperationStatus titanStatus = titanGenericDao.rollback(); + if (titanStatus != TitanOperationStatus.OK) { + result = DBActionCodeEnum.FAIL_GENERAL; + } + return result; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/CommitManager.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/CommitManager.java new file mode 100644 index 0000000000..e802e58f27 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/CommitManager.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.mngr; + +import java.util.List; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.transaction.api.ICommitHandler; +import org.openecomp.sdc.common.transaction.api.TransactionUtils; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.LogMessages; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CommitManager { + private List<ICommitHandler> commitHandlers; + private Integer transactionId; + private String userId, actionType; + private static Logger log = LoggerFactory.getLogger(CommitManager.class.getName()); + + CommitManager(Integer transactionId, String userId, String actionType, List<ICommitHandler> commitHandlers) { + this.commitHandlers = commitHandlers; + this.transactionId = transactionId; + this.userId = userId; + this.actionType = actionType; + + } + + public DBActionCodeEnum transactionCommit() { + log.debug(LogMessages.COMMIT_ACTION_ALL_DB, transactionId, userId, actionType); + DBActionCodeEnum commitResult = DBActionCodeEnum.SUCCESS; + ICommitHandler lastHandler = null; + try { + for (ICommitHandler handler : commitHandlers) { + lastHandler = handler; + log.debug(LogMessages.COMMIT_ACTION_SPECIFIC_DB, transactionId, handler.getDBType().name(), userId, actionType); + DBActionCodeEnum commitCode = handler.doCommit(); + if (commitCode == DBActionCodeEnum.FAIL_GENERAL) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "transactionCommit on DB " + handler.getDBType().name()); + BeEcompErrorManager.getInstance().logBeSystemError("transactionCommit on DB " + handler.getDBType().name()); + log.debug("Commit failed for SdncTransactionID:{} on DB:{}", transactionId, handler.getDBType().name()); + commitResult = DBActionCodeEnum.FAIL_GENERAL; + break; + } + log.debug("Commit succeeded for SdncTransactionID:{} on DB:{}", transactionId, handler.getDBType().name()); + } + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "transactionCommit - on DB " + getDBName(lastHandler)); + BeEcompErrorManager.getInstance().logBeSystemError("transactionCommit - on DB " + getDBName(lastHandler)); + log.debug("Commit failed for SdncTransactionID:{} on DB:{}, Exception message:{}", transactionId, getDBName(lastHandler), e.getMessage(), e); + log.info(TransactionUtils.TRANSACTION_MARKER, "Commit failed for SdncTransactionID:{} on DB:{}", transactionId, getDBName(lastHandler)); + commitResult = DBActionCodeEnum.FAIL_GENERAL; + } + return commitResult; + } + + private String getDBName(ICommitHandler lastHandler) { + String dbName = "Unknown"; + if (lastHandler != null) { + dbName = lastHandler.getDBType().name(); + } + return dbName; + } + + static void setLog(Logger log) { + CommitManager.log = log; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/RollbackManager.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/RollbackManager.java new file mode 100644 index 0000000000..0641524038 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/RollbackManager.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.mngr; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.common.transaction.api.RollbackHandler; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; +import org.openecomp.sdc.common.util.MethodActivationStatusEnum; + +import fj.data.Either; + +public class RollbackManager { + private Map<DBTypeEnum, RollbackHandler> rollBackHandlersMap; + private Integer transactionId; + private String userId, actionType; + + RollbackManager(Integer transactionId, String userId, String actionType, List<RollbackHandler> roleBackHandlers) { + this.transactionId = transactionId; + this.userId = userId; + this.actionType = actionType; + rollBackHandlersMap = new HashMap<>(); + for (RollbackHandler handler : roleBackHandlers) { + rollBackHandlersMap.put(handler.getDBType(), handler); + } + + } + + public DBActionCodeEnum transactionRollback() { + DBActionCodeEnum rollbackResult = DBActionCodeEnum.SUCCESS; + Iterator<RollbackHandler> handlersItr = rollBackHandlersMap.values().iterator(); + while (handlersItr.hasNext()) { + RollbackHandler handler = handlersItr.next(); + DBActionCodeEnum rollbackCode = handler.doRollback(); + if (rollbackCode == DBActionCodeEnum.FAIL_GENERAL) { + rollbackResult = DBActionCodeEnum.FAIL_GENERAL; + } + } + + return rollbackResult; + } + + protected Either<RollbackHandler, MethodActivationStatusEnum> addRollbackHandler(RollbackHandler rollbackHandler) { + Either<RollbackHandler, MethodActivationStatusEnum> result; + if (rollBackHandlersMap.containsKey(rollbackHandler.getDBType())) { + result = Either.right(MethodActivationStatusEnum.NOT_ALLOWED); + } else { + rollBackHandlersMap.put(rollbackHandler.getDBType(), rollbackHandler); + result = Either.left(rollbackHandler); + } + return result; + + } + + protected Either<RollbackHandler, MethodActivationStatusEnum> createRollbackHandler(DBTypeEnum dbType) { + + final DBTypeEnum dbTypeFinal = dbType; + RollbackHandler rollbackHandler = new RollbackHandler(transactionId, userId, actionType) { + + @Override + public DBTypeEnum getDBType() { + return dbTypeFinal; + } + + @Override + protected boolean isRollbackForPersistenceData() { + return true; + } + }; + Either<RollbackHandler, MethodActivationStatusEnum> result = addRollbackHandler(rollbackHandler); + + return result; + } + + protected Either<RollbackHandler, MethodActivationStatusEnum> getRollbackHandler(DBTypeEnum dbType) { + Either<RollbackHandler, MethodActivationStatusEnum> result; + if (rollBackHandlersMap.containsKey(dbType)) { + result = Either.left(rollBackHandlersMap.get(dbType)); + } else { + result = Either.right(MethodActivationStatusEnum.NOT_FOUND); + } + return result; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/TransactionManager.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/TransactionManager.java new file mode 100644 index 0000000000..c401586383 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/TransactionManager.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.mngr; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.annotation.Resource; + +import org.openecomp.sdc.be.dao.impl.ESCatalogDAO; +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.common.datastructure.CapList; +import org.openecomp.sdc.common.transaction.api.ITransactionSdnc; +import org.openecomp.sdc.common.transaction.api.TransactionUtils; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.ActionTypeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component("transactionManager") +public class TransactionManager { + + private static Logger log = LoggerFactory.getLogger(TransactionManager.class.getName()); + + private AtomicInteger transactionIDCounter = new AtomicInteger(0); + + private List<ITransactionSdnc> transactions; + @Resource + private ESCatalogDAO esCatalogDao; + @Resource + private TitanGenericDao titanGenericDao; + + /** + * userId and actionType parameters are used only for logging purposes. + */ + public ITransactionSdnc getTransaction(String userId, ActionTypeEnum actionType) { + if (transactions == null) { + init(); + } + log.debug("TransactionManager creating new SdncTransaction"); + ITransactionSdnc tx = new TransactionSdncImpl(generateTransactionID(), userId, actionType, esCatalogDao, titanGenericDao); + transactions.add(tx); + + return tx; + + } + + private Integer generateTransactionID() { + boolean generatedSuccessfully = false; + int nextId = 0; + + while (!generatedSuccessfully) { + int prevId = transactionIDCounter.get(); + if (prevId > TransactionUtils.TRANSACTION_ID_RESET_LIMIT) { + resetTransactionId(); + } + nextId = prevId + 1; + generatedSuccessfully = transactionIDCounter.compareAndSet(prevId, nextId); + } + return nextId; + } + + private void resetTransactionId() { + + boolean resetSuccessfully = false; + while (!resetSuccessfully) { + int prevId = transactionIDCounter.get(); + resetSuccessfully = transactionIDCounter.compareAndSet(prevId, 0); + } + + } + + private synchronized void init() { + if (transactions == null) { + log.info("TransactionManager Initialized"); + transactions = new CapList<>(TransactionUtils.MAX_SIZE_TRANSACTION_LIST); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/TransactionSdncImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/TransactionSdncImpl.java new file mode 100644 index 0000000000..55eff24fa9 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/common/transaction/mngr/TransactionSdncImpl.java @@ -0,0 +1,313 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.common.transaction.mngr; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.impl.ESCatalogDAO; +import org.openecomp.sdc.be.dao.titan.TitanGenericDao; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.transaction.api.ICommitHandler; +import org.openecomp.sdc.common.transaction.api.IDBAction; +import org.openecomp.sdc.common.transaction.api.ITransactionSdnc; +import org.openecomp.sdc.common.transaction.api.RollbackHandler; +import org.openecomp.sdc.common.transaction.api.TransactionUtils; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.ActionTypeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBActionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.DBTypeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.ESActionTypeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.LogMessages; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.TransactionCodeEnum; +import org.openecomp.sdc.common.transaction.api.TransactionUtils.TransactionStatusEnum; +import org.openecomp.sdc.common.transaction.impl.ESAction; +import org.openecomp.sdc.common.transaction.impl.ESRollbackHandler; +import org.openecomp.sdc.common.transaction.impl.TitanCommitHandler; +import org.openecomp.sdc.common.transaction.impl.TitanRollbackHandler; +import org.openecomp.sdc.common.util.MethodActivationStatusEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class TransactionSdncImpl implements ITransactionSdnc { + private boolean lastActionAlreadyCalled; + private RollbackManager rollbackManager; + private CommitManager commitManager; + private ESCatalogDAO esCatalogDao; + private TitanGenericDao titanGenericDao; + private Integer transactionId; + private TransactionStatusEnum status; + private String userId, actionType; + private static Logger log = LoggerFactory.getLogger(TransactionSdncImpl.class.getName()); + + TransactionSdncImpl(Integer transactionId, String userId, ActionTypeEnum actionTypeEnum, ESCatalogDAO esCatalogDao, TitanGenericDao titanGenericDao) { + this.esCatalogDao = esCatalogDao; + this.titanGenericDao = titanGenericDao; + this.transactionId = transactionId; + this.userId = userId; + actionType = actionTypeEnum.name(); + rollbackManager = new RollbackManager(transactionId, userId, actionType, initRollbackHandlers()); + commitManager = new CommitManager(transactionId, userId, actionType, initCommitHandlers()); + status = TransactionStatusEnum.OPEN; + + } + + private List<ICommitHandler> initCommitHandlers() { + List<ICommitHandler> commitHandlers = new ArrayList<>(); + commitHandlers.add(new TitanCommitHandler(titanGenericDao)); + return commitHandlers; + } + + private List<RollbackHandler> initRollbackHandlers() { + List<RollbackHandler> rolebackHandlers = new ArrayList<>(); + rolebackHandlers.add(new TitanRollbackHandler(transactionId, userId, actionType, titanGenericDao)); + rolebackHandlers.add(new ESRollbackHandler(transactionId, userId, actionType)); + return rolebackHandlers; + } + + private <T> Either<T, TransactionCodeEnum> invokeAction(boolean isLastAction, IDBAction dbAction, DBTypeEnum dbType) { + + Either<T, DBActionCodeEnum> actionResult; + log.debug(LogMessages.INVOKE_ACTION, transactionId, dbType.name(), userId, actionType); + if (isLastAction) { + actionResult = getLastActionResult(dbAction, dbType); + } else { + actionResult = getActionResult(dbAction, dbType); + } + + Either<T, TransactionCodeEnum> result; + boolean isRollbackNedded = actionResult.isRight(); + if (isRollbackNedded) { + TransactionCodeEnum transactionCode = transactionRollback(); + result = Either.right(transactionCode); + } else { + result = Either.left(actionResult.left().value()); + } + return result; + } + + private TransactionCodeEnum transactionRollback() { + + TransactionCodeEnum result; + DBActionCodeEnum transactionRollback = rollbackManager.transactionRollback(); + if (transactionRollback == DBActionCodeEnum.SUCCESS) { + result = TransactionCodeEnum.ROLLBACK_SUCCESS; + log.info(LogMessages.ROLLBACK_SUCCEEDED_GENERAL, transactionId, userId, actionType); + log.info(TransactionUtils.TRANSACTION_MARKER, LogMessages.ROLLBACK_SUCCEEDED_GENERAL, transactionId, userId, actionType); + + } else { + result = TransactionCodeEnum.ROLLBACK_FAILED; + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "transactionCommit for transaction " + transactionId); + BeEcompErrorManager.getInstance().logBeSystemError("transactionCommit for transaction " + transactionId); + + log.info(LogMessages.ROLLBACK_FAILED_GENERAL, transactionId, userId, actionType); + log.debug(TransactionUtils.TRANSACTION_MARKER, LogMessages.ROLLBACK_FAILED_GENERAL, transactionId, userId, actionType); + } + return result; + } + + public <T> Either<T, TransactionCodeEnum> invokeTitanAction(boolean isLastAction, IDBAction dbAction) { + Either<T, TransactionCodeEnum> result; + if (status == TransactionStatusEnum.OPEN) { + result = invokeAction(isLastAction, dbAction, DBTypeEnum.TITAN); + } else { + result = handleActionOnClosedTransaction(); + } + updateTransactionStatus(result); + return result; + } + + public <T> Either<T, TransactionCodeEnum> invokeGeneralDBAction(boolean isLastAction, DBTypeEnum dbType, IDBAction dbAction, IDBAction dbRollbackAction) { + + Either<T, TransactionCodeEnum> result; + MethodActivationStatusEnum addingHandlerResult; + if (status == TransactionStatusEnum.OPEN) { + log.debug(LogMessages.PRE_INVOKE_ACTION, transactionId, dbType.name(), userId, actionType); + Either<RollbackHandler, MethodActivationStatusEnum> eitherRollbackHandler = rollbackManager.getRollbackHandler(dbType); + + if (eitherRollbackHandler.isLeft()) { + RollbackHandler rollbackHandler = eitherRollbackHandler.left().value(); + addingHandlerResult = rollbackHandler.addRollbackAction(dbRollbackAction); + } else { + addingHandlerResult = addToNewRollbackHandler(dbType, dbRollbackAction); + } + + if (addingHandlerResult == MethodActivationStatusEnum.SUCCESS) { + result = invokeAction(isLastAction, dbAction, dbType); + } else { + result = Either.right(TransactionCodeEnum.PREPARE_ROLLBACK_FAILED); + } + } else { + result = handleActionOnClosedTransaction(); + } + updateTransactionStatus(result); + return result; + } + + private MethodActivationStatusEnum addToNewRollbackHandler(DBTypeEnum dbType, IDBAction dbRollbackAction) { + log.debug(LogMessages.CREATE_ROLLBACK_HANDLER, dbType.name(), transactionId, userId, actionType); + MethodActivationStatusEnum result; + + Either<RollbackHandler, MethodActivationStatusEnum> eitherRollbackHandler = rollbackManager.createRollbackHandler(dbType); + if (eitherRollbackHandler.isRight()) { + result = eitherRollbackHandler.right().value(); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "TransactionManager - addToNewRollbackHandler"); + BeEcompErrorManager.getInstance().logBeSystemError("TransactionManager - addToNewRollbackHandler"); + log.info(LogMessages.FAILED_CREATE_ROLLBACK, dbType.name(), transactionId, userId, actionType); + log.debug(TransactionUtils.TRANSACTION_MARKER, LogMessages.FAILED_CREATE_ROLLBACK, dbType.name(), transactionId, userId, actionType); + } else { + RollbackHandler rollbackHandler = eitherRollbackHandler.left().value(); + rollbackHandler.addRollbackAction(dbRollbackAction); + result = MethodActivationStatusEnum.SUCCESS; + } + + return result; + } + + public Either<DBActionCodeEnum, TransactionCodeEnum> invokeESAction(boolean isLastAction, ESActionTypeEnum esActiontype, ESArtifactData artifactData) { + + Either<DBActionCodeEnum, TransactionCodeEnum> result; + if (status == TransactionStatusEnum.OPEN) { + Either<RollbackHandler, MethodActivationStatusEnum> eitherEsHandler = rollbackManager.getRollbackHandler(DBTypeEnum.ELASTIC_SEARCH); + if (eitherEsHandler.isRight()) { + result = Either.right(TransactionCodeEnum.INTERNAL_ERROR); + } else { + ESRollbackHandler esHandler = (ESRollbackHandler) eitherEsHandler.left().value(); + + Either<ESAction, MethodActivationStatusEnum> eitherEsRollbackAction = esHandler.buildEsRollbackAction(esCatalogDao, artifactData, esActiontype); + if (eitherEsRollbackAction.isLeft()) { + esHandler.addRollbackAction(eitherEsRollbackAction.left().value()); + result = invokeAction(isLastAction, new ESAction(esCatalogDao, artifactData, esActiontype), DBTypeEnum.ELASTIC_SEARCH); + } else { + result = Either.right(TransactionCodeEnum.PREPARE_ROLLBACK_FAILED); + } + + } + } else { + result = handleActionOnClosedTransaction(); + } + updateTransactionStatus(result); + return result; + } + + private <T> void updateTransactionStatus(Either<T, TransactionCodeEnum> result) { + if (result.isRight()) { + updateTransactionStatus(result.right().value()); + } + + } + + private <T> Either<T, TransactionCodeEnum> handleActionOnClosedTransaction() { + Either<T, TransactionCodeEnum> result = Either.right(TransactionCodeEnum.TRANSACTION_CLOSED); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "TransactionManager - handleActionOnClosedTransaction"); + log.debug(LogMessages.ACTION_ON_CLOSED_TRANSACTION, transactionId, userId, actionType); + log.info(TransactionUtils.TRANSACTION_MARKER, LogMessages.ACTION_ON_CLOSED_TRANSACTION, transactionId, userId, actionType); + return result; + } + + private <T> Either<T, DBActionCodeEnum> getLastActionResult(IDBAction dataBaseAction, DBTypeEnum dbType) { + Either<T, DBActionCodeEnum> result; + if (isLastActionAlreadyCalled()) { + result = Either.right(DBActionCodeEnum.FAIL_MULTIPLE_LAST_ACTION); + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "TransactionManager - getLastActionResult"); + BeEcompErrorManager.getInstance().logBeSystemError("TransactionManager - getLastActionResult"); + log.debug(LogMessages.DOUBLE_FINISH_FLAG_ACTION, transactionId, dbType.name(), userId, actionType); + log.info(TransactionUtils.TRANSACTION_MARKER, LogMessages.DOUBLE_FINISH_FLAG_ACTION, transactionId, dbType.name(), userId, actionType); + } else { + setLastActionAlreadyCalled(true); + result = getActionResult(dataBaseAction, dbType); + } + return result; + } + + private <T> Either<T, DBActionCodeEnum> getActionResult(IDBAction dataBaseAction, DBTypeEnum dbType) { + Either<T, DBActionCodeEnum> result; + try { + T doAction = dataBaseAction.doAction(); + result = Either.left(doAction); + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "TransactionManager - getActionResult"); + BeEcompErrorManager.getInstance().logBeSystemError("TransactionManager - getActionResult"); + log.debug(LogMessages.DB_ACTION_FAILED_WITH_EXCEPTION, dbType.name(), transactionId, e.getMessage(), userId, actionType, e); + log.info(TransactionUtils.TRANSACTION_MARKER, LogMessages.DB_ACTION_FAILED_WITH_EXCEPTION, dbType.name(), transactionId, e.getMessage(), userId, actionType); + + result = Either.right(DBActionCodeEnum.FAIL_GENERAL); + } + return result; + } + + public TransactionCodeEnum finishTransaction() { + TransactionCodeEnum result; + if (status == TransactionStatusEnum.OPEN) { + DBActionCodeEnum transactionCommit = commitManager.transactionCommit(); + if (transactionCommit == DBActionCodeEnum.SUCCESS) { + result = TransactionCodeEnum.SUCCESS; + status = TransactionStatusEnum.CLOSED; + } else { + result = transactionRollback(); + } + } else { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "TransactionManager - finishTransaction"); + BeEcompErrorManager.getInstance().logBeSystemError("TransactionManager - finishTransaction"); + log.debug(LogMessages.COMMIT_ON_CLOSED_TRANSACTION, transactionId, status.name(), userId, actionType); + log.info(TransactionUtils.TRANSACTION_MARKER, LogMessages.COMMIT_ON_CLOSED_TRANSACTION, transactionId, status.name(), userId, actionType); + result = TransactionCodeEnum.TRANSACTION_CLOSED; + } + updateTransactionStatus(result); + return result; + } + + private void updateTransactionStatus(TransactionCodeEnum result) { + switch (result) { + case SUCCESS: + status = TransactionStatusEnum.CLOSED; + break; + case ROLLBACK_SUCCESS: + status = TransactionStatusEnum.CLOSED; + break; + case ROLLBACK_FAILED: + status = TransactionStatusEnum.FAILED_ROLLBACK; + break; + default: + break; + } + + } + + private boolean isLastActionAlreadyCalled() { + return lastActionAlreadyCalled; + } + + private void setLastActionAlreadyCalled(boolean lastAction) { + this.lastActionAlreadyCalled = lastAction; + } + + static void setLog(Logger log) { + TransactionSdncImpl.log = log; + } + + TransactionStatusEnum getStatus() { + return status; + } +} |