/* * Copyright © 2016-2018 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openecomp.sdc.action.dao.impl; import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; import static com.datastax.driver.core.querybuilder.QueryBuilder.in; import static com.datastax.driver.core.querybuilder.QueryBuilder.set; import static org.onap.logging.ref.slf4j.ONAPLogConstants.ResponseStatus.COMPLETE; import static org.onap.logging.ref.slf4j.ONAPLogConstants.ResponseStatus.ERROR; import static org.openecomp.core.nosqldb.impl.cassandra.CassandraSessionFactory.getSession; import static org.openecomp.sdc.action.ActionConstants.FILTER_TYPE_CATEGORY; import static org.openecomp.sdc.action.ActionConstants.FILTER_TYPE_MODEL; import static org.openecomp.sdc.action.ActionConstants.FILTER_TYPE_NAME; import static org.openecomp.sdc.action.ActionConstants.FILTER_TYPE_NONE; import static org.openecomp.sdc.action.ActionConstants.FILTER_TYPE_OPEN_ECOMP_COMPONENT; import static org.openecomp.sdc.action.ActionConstants.FILTER_TYPE_VENDOR; import static org.openecomp.sdc.action.ActionConstants.STATUS; import static org.openecomp.sdc.action.ActionConstants.TARGET_ENTITY; import static org.openecomp.sdc.action.ActionConstants.TARGET_ENTITY_DB; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_ARTIFACT_DEL_LOCKED_OTHER_USER; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_ARTIFACT_DEL_LOCKED_OTHER_USER_CODE; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_ENTITY_NOT_EXIST; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_ENTITY_NOT_EXIST_CODE; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_INTERNAL_SERVER_ERR_CODE; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_NOT_LOCKED_CODE; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_NOT_LOCKED_MSG; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_QUERY_FAILURE_CODE; import static org.openecomp.sdc.action.errors.ActionErrorConstants.ACTION_QUERY_FAILURE_MSG; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Row; import com.datastax.driver.core.Statement; import com.datastax.driver.core.exceptions.NoHostAvailableException; import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.mapping.Mapper; import com.datastax.driver.mapping.Result; import com.datastax.driver.mapping.annotations.Accessor; import com.datastax.driver.mapping.annotations.Query; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.openecomp.core.dao.impl.CassandraBaseDao; import org.openecomp.core.nosqldb.api.NoSqlDb; import org.openecomp.core.nosqldb.factory.NoSqlDbFactory; import org.openecomp.core.utilities.json.JsonUtil; import org.openecomp.sdc.action.ActionConstants; import org.openecomp.sdc.action.dao.ActionDao; import org.openecomp.sdc.action.dao.types.ActionEntity; import org.openecomp.sdc.action.dao.types.OpenEcompComponentEntity; import org.openecomp.sdc.action.errors.ActionException; import org.openecomp.sdc.action.logging.CategoryLogLevel; import org.openecomp.sdc.action.types.Action; import org.openecomp.sdc.action.types.ActionStatus; import org.openecomp.sdc.action.types.ActionSubOperation; import org.openecomp.sdc.action.types.OpenEcompComponent; import org.openecomp.sdc.action.util.ActionUtil; import org.openecomp.sdc.logging.api.Logger; import org.openecomp.sdc.logging.api.LoggerFactory; import org.openecomp.sdc.versioning.ActionVersioningManagerFactory; import org.openecomp.sdc.versioning.dao.VersionInfoDao; import org.openecomp.sdc.versioning.dao.VersionInfoDaoFactory; import org.openecomp.sdc.versioning.dao.VersionInfoDeletedDao; import org.openecomp.sdc.versioning.dao.VersionInfoDeletedDaoFactory; import org.openecomp.sdc.versioning.dao.types.Version; import org.openecomp.sdc.versioning.dao.types.VersionInfoDeletedEntity; import org.openecomp.sdc.versioning.dao.types.VersionInfoEntity; import org.openecomp.sdc.versioning.types.VersionableEntityMetadata; import org.slf4j.MDC; public class ActionDaoImpl extends CassandraBaseDao implements ActionDao { private static final String FOR_VERSIONS = " for versions "; private static final String VERSION = "version"; private static final String ACTION = "Action"; private static NoSqlDb noSqlDb = NoSqlDbFactory.getInstance().createInterface(); private static Mapper mapper = noSqlDb.getMappingManager().mapper(ActionEntity.class); private static ActionAccessor accessor = noSqlDb.getMappingManager().createAccessor(ActionAccessor.class); private static VersionInfoDao versionInfoDao = VersionInfoDaoFactory.getInstance().createInterface(); private static VersionInfoDeletedDao versionInfoDeletedDao = VersionInfoDeletedDaoFactory.getInstance().createInterface(); private final Logger log = LoggerFactory.getLogger(this.getClass().getName()); @Override public void registerVersioning(String versionableEntityType) { ActionVersioningManagerFactory.getInstance().createInterface().register(versionableEntityType, new VersionableEntityMetadata(mapper.getTableMetadata().getName(), mapper.getTableMetadata().getPartitionKey().get(0).getName(), mapper.getTableMetadata().getPartitionKey().get(1).getName())); } @Override public Action createAction(Action action) { try { ActionUtil.actionLogPreProcessor(ActionSubOperation.CREATE_ACTION_ENTITY, TARGET_ENTITY_DB); this.create(action.toEntity()); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); return action; } catch (NoHostAvailableException exception) { logGenericException(exception); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } } @Override public Action updateAction(Action action) { try { log.debug(" entering updateAction with actionUUID= " + action.getActionUuId()); ActionUtil.actionLogPreProcessor(ActionSubOperation.UPDATE_ACTION, TARGET_ENTITY_DB); this.update(action.toEntity()); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); log.debug(" exit updateAction with actionUUID= " + action.getActionUuId()); return action; } catch (NoHostAvailableException exception) { logGenericException(exception); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } } @Override public void deleteAction(String actionInvariantUuId) { try { log.debug("entering deleteAction with actionInvariantUuId = " + actionInvariantUuId); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTION_VERSION, TARGET_ENTITY_DB); VersionInfoDeletedEntity activeVersionEntity = versionInfoDeletedDao .get(new VersionInfoDeletedEntity(ActionConstants.ACTION_VERSIONABLE_TYPE, actionInvariantUuId)); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); Version activeVersion = activeVersionEntity.getActiveVersion(); Statement getNameFromInvUuId = QueryBuilder.select().column("name").from("dox", ACTION) .where(eq("actioninvariantuuid", actionInvariantUuId)).and(in(VERSION, activeVersion)); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_NAME_BY_ACTIONINVID, TARGET_ENTITY_DB); ResultSet results = getSession().execute(getNameFromInvUuId); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); if (!results.isExhausted()) { String name = results.one().getString("name"); List versions = getVersionsByName(name); updateActionStatusForDelete(actionInvariantUuId, versions); } } catch (NoHostAvailableException noHostAvailableException) { logGenericException(noHostAvailableException); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } log.debug("exit deleteAction"); } @Override public List getFilteredActions(String filterType, String filterId) { List actions = new ArrayList<>(); Result result = null; log.debug(" entering getFilteredActions By filterType = " + filterType + " With value = " + filterId); try { switch (filterType) { case FILTER_TYPE_VENDOR: ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_VENDOR, TARGET_ENTITY_DB); result = accessor.getActionsByVendor(filterId); ActionUtil.actionLogPostProcessor(COMPLETE); log.metrics(""); break; case FILTER_TYPE_CATEGORY: ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_CATEGORY, TARGET_ENTITY_DB); result = accessor.getActionsByCategory(filterId); ActionUtil.actionLogPostProcessor(COMPLETE); log.metrics(""); break; case FILTER_TYPE_MODEL: ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_MODEL, TARGET_ENTITY_DB); result = accessor.getActionsByModel(filterId); ActionUtil.actionLogPostProcessor(COMPLETE); log.metrics(""); break; case FILTER_TYPE_OPEN_ECOMP_COMPONENT: ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_COMPONENT, TARGET_ENTITY_DB); result = accessor.getActionsByOpenEcompComponent(filterId); ActionUtil.actionLogPostProcessor(COMPLETE); log.metrics(""); break; case FILTER_TYPE_NONE: ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ALL_ACTIONS, TARGET_ENTITY_DB); result = accessor.getAllActions(); ActionUtil.actionLogPostProcessor(COMPLETE); log.metrics(""); break; case FILTER_TYPE_NAME: ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONINVID_BY_NAME, TARGET_ENTITY_DB); result = accessor.getInvIdByName(filterId); ActionUtil.actionLogPostProcessor(COMPLETE); log.metrics(""); List actionEntities = result.all(); if (actionEntities != null && !actionEntities.isEmpty()) { String actionInvariantUuId = actionEntities.get(0).getActionInvariantUuId(); if (actionInvariantUuId != null) { return getActionsByActionInvariantUuId(actionInvariantUuId); } else { return actions; } } break; default: break; } if (result != null) { actions.addAll(result.all().stream().map(ActionEntity::toDto).collect(Collectors.toList())); } log.debug(" exit getFilteredActions By filterType = " + filterType + " With value = " + filterId); } catch (NoHostAvailableException noHostAvailableException) { logGenericException(noHostAvailableException); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } return actions; } @Override public Action getActionsByActionUuId(String actionUuId) { try { log.debug(" entering getActionsByActionUuId with actionUUID= " + actionUuId); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_ACTIONUUID, TARGET_ENTITY_DB); Result result = accessor.actionInvariantUuId(actionUuId); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); if (result != null) { log.debug(" exit getActionsByActionUuId with actionUUID= " + actionUuId); ActionEntity entity = result.one(); if (entity != null) { return entity.toDto(); } } log.debug(" exit getActionsByActionUuId with actionUUID= " + actionUuId); return null; } catch (NoHostAvailableException noHostAvailableException) { logGenericException(noHostAvailableException); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } } @Override public List getOpenEcompComponents() { List openEcompComponents = new ArrayList<>(); Result result; try { log.debug(" entering getOpenEcompComponents "); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_OPEN_ECOMP_COMPONENTS_ENTITY, TARGET_ENTITY_DB); result = accessor.getOpenEcompComponents(); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); if (result != null) { openEcompComponents.addAll(result.all().stream().map(OpenEcompComponentEntity::toDto).collect(Collectors.toList())); } } catch (NoHostAvailableException noHostAvailableException) { logGenericException(noHostAvailableException); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } log.debug(" exit getOpenEcompComponents "); return openEcompComponents; } @Override public List getActionsByActionInvariantUuId(String actionInvariantUuId) { List actions = new ArrayList(); try { log.debug(" entering getActionsByActionInvariantUuId with actionInvariantUuId= " + actionInvariantUuId); Set viewableVersions = new HashSet<>(); VersionPredicate filter = new VersionPredicate(); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTION_VERSION, TARGET_ENTITY_DB); VersionInfoEntity versionInfoEntity = versionInfoDao .get(new VersionInfoEntity(ActionConstants.ACTION_VERSIONABLE_TYPE, actionInvariantUuId)); if (versionInfoEntity == null) { // Check for action in the Delete version info table VersionInfoDeletedEntity versionInfoDeletedEntity = versionInfoDeletedDao .get(new VersionInfoDeletedEntity(ActionConstants.ACTION_VERSIONABLE_TYPE, actionInvariantUuId)); if (versionInfoDeletedEntity != null) { viewableVersions = versionInfoDeletedEntity.getViewableVersions(); // Remove intermediate minor versions from viewable versions if (versionInfoDeletedEntity.getActiveVersion() != null) { filter.activeVersion = versionInfoDeletedEntity.getActiveVersion(); filter.finalVersion = versionInfoDeletedEntity.getLatestFinalVersion(); viewableVersions.removeIf(filter::isIntermediateMinorVersion); } } } else { viewableVersions = versionInfoEntity.getViewableVersions(); // Remove intermediate minor versions from viewable versions if (versionInfoEntity.getActiveVersion() != null) { filter.activeVersion = versionInfoEntity.getActiveVersion(); filter.finalVersion = versionInfoEntity.getLatestFinalVersion(); viewableVersions.removeIf(filter::isIntermediateMinorVersion); } // Add candidate version if available if (versionInfoEntity.getCandidate() != null) { viewableVersions.add(versionInfoEntity.getCandidate().getVersion()); } } MDC.put(TARGET_ENTITY, TARGET_ENTITY_DB); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); log.debug("Found " + viewableVersions + " viewable version for action with actionInvariantUuId " + actionInvariantUuId); // Fetch action data for the viewable versions if (!viewableVersions.isEmpty()) { ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_ACTIONINVID, TARGET_ENTITY_DB); Result result = accessor.getActionsByInvId(actionInvariantUuId, new ArrayList<>(viewableVersions)); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); if (result != null) { actions.addAll(result.all().stream().map(ActionEntity::toDto).collect(Collectors.toList())); } } } catch (NoHostAvailableException noHostAvailableException) { logGenericException(noHostAvailableException); throw new ActionException(ACTION_INTERNAL_SERVER_ERR_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG); } log.debug(" exit getActionsByActionInvariantUuId with actionInvariantUuId= " + actionInvariantUuId); return actions; } @Override public Action getLockedAction(String actionInvariantUuId, String user) { log.debug(" entering getLockedAction with actionInvariantUuId= " + actionInvariantUuId); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTION_VERSION, TARGET_ENTITY_DB); Action action = null; VersionInfoEntity versionInfoEntity = versionInfoDao.get(new VersionInfoEntity(ActionConstants.ACTION_VERSIONABLE_TYPE, actionInvariantUuId)); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); if (versionInfoEntity != null) { if (versionInfoEntity.getCandidate() != null) { String actionUser = versionInfoEntity.getCandidate().getUser(); if (actionUser != null && actionUser.equals(user)) { Set versions = new HashSet<>(); versions.add(versionInfoEntity.getCandidate().getVersion()); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTIONENTITY_BY_ACTIONINVID, TARGET_ENTITY_DB); Result result = accessor.getActionsByInvId(actionInvariantUuId, new ArrayList<>(versions)); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); if (result != null) { ActionEntity actionEntity = result.one(); action = actionEntity != null ? actionEntity.toDto() : null; } } else { throw new ActionException(ACTION_ARTIFACT_DEL_LOCKED_OTHER_USER_CODE, String.format(ACTION_ARTIFACT_DEL_LOCKED_OTHER_USER, actionUser)); } } else { throw new ActionException(ACTION_NOT_LOCKED_CODE, ACTION_NOT_LOCKED_MSG); } } else { throw new ActionException(ACTION_ENTITY_NOT_EXIST_CODE, ACTION_ENTITY_NOT_EXIST); } return action; } private void logGenericException(Exception exception) { ActionUtil.actionLogPostProcessor(ERROR, ACTION_QUERY_FAILURE_CODE, ACTION_ENTITY_INTERNAL_SERVER_ERROR_MSG, false); log.metrics(""); ActionUtil.actionErrorLogProcessor(CategoryLogLevel.FATAL, ACTION_QUERY_FAILURE_CODE, ACTION_QUERY_FAILURE_MSG); log.error(exception.getMessage()); } @Override protected Mapper getMapper() { return mapper; } @Override protected Object[] getKeys(ActionEntity entity) { return new Object[]{entity.getActionInvariantUuId(), entity.getVersion()}; } @Override public Collection list(ActionEntity entity) { return accessor.getAllActions().all(); } private void updateActionStatusForDelete(String actionInvariantUuId, List versions) { log.debug("entering updateActionStatusForDelete with actionInvariantUuId = " + actionInvariantUuId + FOR_VERSIONS + versions); ActionUtil.actionLogPreProcessor(ActionSubOperation.UPDATE_ACTION_STATUS, TARGET_ENTITY_DB); // Update the status column of action table Statement updateStatusStatement = QueryBuilder.update("dox", ACTION).with(set("status", ActionStatus.Deleted.name())) .where(eq("actioninvariantuuid", actionInvariantUuId)).and(in(VERSION, versions)); getSession().execute(updateStatusStatement); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); // Update the status in the data field of action table updateStatusInActionData(actionInvariantUuId, versions, ActionStatus.Deleted); log.debug("exit updateActionStatusForDelete with actionInvariantUuId = " + actionInvariantUuId + FOR_VERSIONS + versions); } /** * Update status for a list of versions for a given action. * * @param actionInvariantUuId Invariant UUID of the action. * @param versions List of {@link Version} for which the status has to be updated. * @param status The status value. */ private void updateStatusInActionData(String actionInvariantUuId, List versions, ActionStatus status) { log.debug("entering updateStatusInActionData for actionInvariantUuId = " + actionInvariantUuId + " and status = " + status + FOR_VERSIONS + versions); for (Version v : versions) { ActionEntity entity = this.get(new ActionEntity(actionInvariantUuId, v)); String currentData = entity.getData(); Map currentDataMap = JsonUtil.json2Object(currentData, LinkedHashMap.class); currentDataMap.put(STATUS, status); String updatedActionData = JsonUtil.object2Json(currentDataMap); entity.setData(updatedActionData); this.updateAction(entity.toDto()); } log.debug("exit updateStatusInActionData"); } /** * Get list of all major and minor version values for a given action by action name. * * @param name Name of the action. * @return List of {@link Version} objects for the action. */ private List getVersionsByName(String name) { log.debug("entering getVersionsByName for Action Name = " + name); ActionUtil.actionLogPreProcessor(ActionSubOperation.GET_ACTION_VERSION, TARGET_ENTITY_DB); Statement statement = QueryBuilder.select().column(VERSION).from("dox", ACTION).where(eq("name", name)); ResultSet results = getSession().execute(statement); ActionUtil.actionLogPostProcessor(COMPLETE, null, "", false); log.metrics(""); List versionList = new ArrayList<>(); for (Row row : results) { Version version = row.get(VERSION, Version.class); versionList.add(version); } log.debug("exit getVersionsByName for Action Name = " + name); return versionList; } @Accessor interface ActionAccessor { @Query("SELECT * FROM Action") Result getAllActions(); @Query("SELECT * FROM Action where actionInvariantUuId = ? and version in ? ") Result getActionsByInvId(String actionInvariantUuId, List versions); @Query("SELECT * FROM Action where supportedModels CONTAINS ?") Result getActionsByModel(String resource); @Query("SELECT * FROM Action where supportedComponents CONTAINS ?") Result getActionsByOpenEcompComponent(String resource); @Query("SELECT * FROM Action where vendor_list CONTAINS ?") Result getActionsByVendor(String vendor); @Query("SELECT * FROM Action where category_list CONTAINS ?") Result getActionsByCategory(String vendor); @Query("SELECT actionInvariantUuId FROM Action where name = ? limit 1") Result getInvIdByName(String name); @Query("SELECT * FROM EcompComponent") Result getOpenEcompComponents(); @Query("SELECT * FROM Action where actionUUID = ?") Result actionInvariantUuId(String actionUuId); } class VersionPredicate { Version activeVersion; Version finalVersion; public boolean isIntermediateMinorVersion(Version version) { int activeMajorVersion = activeVersion.getMajor(); int activeMinorVersion = activeVersion.getMinor(); int currentMinorVersion = version.getMinor(); int currentMajorVersion = version.getMajor(); if (finalVersion != null) { if (finalVersion.getMajor() == activeMajorVersion && currentMajorVersion == finalVersion.getMajor()) { if (currentMinorVersion < activeMinorVersion && currentMinorVersion != 0) { return true; } } else { return false; } } else { if (!version.equals(activeVersion)) { return true; } } return false; } } }