diff options
author | vasraz <vasyl.razinkov@est.tech> | 2023-05-24 17:30:41 +0100 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2023-06-08 19:44:38 +0000 |
commit | 98f08c1f9b617e670cd4c71321c9152e8f63b18c (patch) | |
tree | 5823c85f9c16dd24918438e251238ba770532a91 /catalog-be/src/main | |
parent | 1c4fe946f65fb4e7db5cc5d4225b14ec6cc22306 (diff) |
Update external query api with new query params
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Change-Id: Ib4970d4f57f9e236f520ca1925915d288c9c5236
Issue-ID: SDC-4409
Diffstat (limited to 'catalog-be/src/main')
5 files changed, 351 insertions, 288 deletions
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 index 1d554651b8..363b8d64df 100644 --- 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 @@ -38,7 +38,12 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; @@ -56,6 +61,7 @@ import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; 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.category.CategoryDataDefinition; import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; @@ -66,6 +72,7 @@ import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; 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.externalapi.servlet.representation.VersionFilterEnum; import org.openecomp.sdc.be.model.ArtifactType; import org.openecomp.sdc.be.model.BaseType; import org.openecomp.sdc.be.model.CatalogUpdateTimestamp; @@ -123,7 +130,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsOperations artifactToscaOperation, IElementOperation elementOperation, UserBusinessLogic userAdminManager) { super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation, - artifactToscaOperation); + artifactToscaOperation); this.elementOperation = elementOperation; } @@ -160,7 +167,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse( - Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) { + Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) { Map<String, List<? extends Component>> arrayResponse = new HashMap<>(); if (setResponse.isLeft()) { for (Map.Entry<String, Set<? extends Component>> entry : setResponse.left().value().entrySet()) { @@ -218,10 +225,10 @@ public class ElementBusinessLogic extends BaseBusinessLogic { Set<LifecycleStateEnum> lastStateStates) { try { Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade - .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE); + .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE); if (resources.isLeft()) { Either<Set<Service>, StorageOperationStatus> services = toscaOperationFacade - .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE); + .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE); if (services.isLeft()) { Map<String, Set<? extends Component>> result = new HashMap<>(); result.put(SERVICES, services.left().value()); @@ -241,7 +248,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) { Either<Set<Product>, StorageOperationStatus> products = toscaOperationFacade - .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT); + .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT); if (products.isLeft()) { Map<String, Set<? extends Component>> result = new HashMap<>(); result.put("products", products.left().value()); @@ -293,16 +300,16 @@ public class ElementBusinessLogic extends BaseBusinessLogic { 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()); + .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); + componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); + .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); return Either.right(responseFormat); } @@ -325,7 +332,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { if (Boolean.FALSE.equals(isCategoryUnique)) { log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName); + .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName); handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); return Either.right(responseFormat); } @@ -333,7 +340,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { if (createCategoryByType.isRight()) { log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName); + .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName); handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType); return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value())); } @@ -397,7 +404,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY); CategoryDefinition categoryDefinition; Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId, - componentTypeEnum); + componentTypeEnum); if (validateCategoryExists.isRight()) { log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId); ResponseFormat responseFormat = validateCategoryExists.right().value(); @@ -409,16 +416,16 @@ public class ElementBusinessLogic extends BaseBusinessLogic { 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()); + .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); + componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); + .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); return Either.right(responseFormat); } @@ -426,10 +433,10 @@ public class ElementBusinessLogic extends BaseBusinessLogic { subCategory.setNormalizedName(normalizedName); // Uniqueness under this category Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation - .isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId); + .isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId); if (subCategoryUniqueForCategory.isRight()) { log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, - normalizedName, componentType); + normalizedName, componentType); ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value()); handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); return Either.right(responseFormat); @@ -437,9 +444,9 @@ public class ElementBusinessLogic extends BaseBusinessLogic { Boolean isSubUnique = subCategoryUniqueForCategory.left().value(); if (Boolean.FALSE.equals(isSubUnique)) { log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, - normalizedName, componentType); + normalizedName, componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName); + .getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName); handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType); return Either.right(responseFormat); } @@ -455,7 +462,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { // his subcategory name will be Router-->kUKU. Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation - .getSubCategoryUniqueForType(childNodeType, normalizedName); + .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()); @@ -469,7 +476,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { subCategory.setName(subCategoryName); ///////////////////////////////////////////// Validations end Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation - .createSubCategory(parentCategoryId, subCategory, childNodeType); + .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()); @@ -566,7 +573,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { // Validate category CategoryDefinition categoryDefinition; Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId, - componentTypeEnum); + componentTypeEnum); if (validateCategoryExists.isRight()) { log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId); ResponseFormat responseFormat = validateCategoryExists.right().value(); @@ -578,7 +585,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { // Validate subcategory SubCategoryDefinition subCategoryDefinition; Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId, - componentTypeEnum); + componentTypeEnum); if (validateSubCategoryExists.isRight()) { log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId); ResponseFormat responseFormat = validateSubCategoryExists.right().value(); @@ -590,16 +597,16 @@ public class ElementBusinessLogic extends BaseBusinessLogic { 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()); + .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); + componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); + .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue()); handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); return Either.right(responseFormat); } @@ -607,10 +614,10 @@ public class ElementBusinessLogic extends BaseBusinessLogic { grouping.setNormalizedName(normalizedName); // Uniqueness under this category Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation - .isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId); + .isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId); if (groupingUniqueForSubCategory.isRight()) { log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, - normalizedName, componentType); + normalizedName, componentType); ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value()); handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); return Either.right(responseFormat); @@ -618,9 +625,9 @@ public class ElementBusinessLogic extends BaseBusinessLogic { Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value(); if (Boolean.FALSE.equals(isGroupingUnique)) { log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, - normalizedName, componentType); + normalizedName, componentType); ResponseFormat responseFormat = componentsUtils - .getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName); + .getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName); handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType); return Either.right(responseFormat); } @@ -659,7 +666,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { 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); + componentType); return Either.left(groupingCreated); } @@ -709,7 +716,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { User user = validateUserExists(userId); // GET resource categories Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation - .getAllCategories(NodeTypeEnum.ResourceNewCategory, false); + .getAllCategories(NodeTypeEnum.ResourceNewCategory, false); if (getResourceCategoriesByType.isRight()) { responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value()); componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat); @@ -718,7 +725,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { categories.setResourceCategories(getResourceCategoriesByType.left().value()); // GET service categories Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation - .getAllCategories(NodeTypeEnum.ServiceNewCategory, false); + .getAllCategories(NodeTypeEnum.ServiceNewCategory, false); if (getServiceCategoriesByType.isRight()) { responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value()); componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.SERVICE.getValue(), responseFormat); @@ -786,12 +793,12 @@ public class ElementBusinessLogic extends BaseBusinessLogic { 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); + 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); + componentTypeEnum); return Either.right(responseFormat); } return Either.left(true); @@ -799,7 +806,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) { boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY - || categoryType == CategoryTypeEnum.SUBCATEGORY); + || categoryType == CategoryTypeEnum.SUBCATEGORY); boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY; boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can @@ -827,7 +834,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { ResponseFormat responseFormat; if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) { responseFormat = componentsUtils - .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), ""); + .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), ""); } else { responseFormat = componentsUtils.getResponseFormat(actionStatus); } @@ -845,7 +852,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { ResponseFormat responseFormat; if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) { responseFormat = componentsUtils - .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), ""); + .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), ""); } else { responseFormat = componentsUtils.getResponseFormat(actionStatus); } @@ -903,7 +910,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(List<OriginTypeEnum> excludeTypes) { try { return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes) - .bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err))); + .bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err))); } finally { janusGraphDao.commit(); } @@ -911,7 +918,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) { Map<String, List<CatalogComponent>> map = components.stream() - .collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType()))); + .collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType()))); // fixed response for UI!!! UI need to receive always map! if (map == null) { map = new HashMap<>(); @@ -932,7 +939,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } } - public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, + public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, Object> filters, String query) { ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType); if (query != null) { @@ -940,10 +947,10 @@ public class ElementBusinessLogic extends BaseBusinessLogic { 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())); + FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString())); } } - if (filters == null || filters.isEmpty()) { + if (MapUtils.isEmpty(filters)) { Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false); if (componentsList.isRight()) { return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value()))); @@ -955,53 +962,81 @@ public class ElementBusinessLogic extends BaseBusinessLogic { if (result.isRight()) { 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))); + .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 + 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()); } - private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType, + private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, Object> filters, ComponentTypeEnum assetType, boolean inTransaction) { Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>()); if (assetType == ComponentTypeEnum.RESOURCE) { assetResult = getFilteredResources(filters, inTransaction); } else if (assetType == ComponentTypeEnum.SERVICE) { - assetResult = getFilteredServices(filters, inTransaction); + assetResult = getFilteredServices(filters); } return assetResult; } - private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters, - boolean inTransaction) { - Either<List<T>, StorageOperationStatus> components = null; - String categoryName = filters.get(FilterKeyEnum.CATEGORY); - String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS); - DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus); - if (distributionStatus != null && distEnum == null) { - filters.remove(FilterKeyEnum.CATEGORY); - return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND); - } - if (categoryName != null) { // primary filter - components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null); - if (components.isLeft() && distEnum != null) {// secondary filter - Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum; - return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList())); + private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, Object> filters) { + final String distributionStatus = (String) filters.get(FilterKeyEnum.DISTRIBUTION_STATUS); + final DistributionStatusEnum distEnum; + if (StringUtils.isNotBlank(distributionStatus)) { + distEnum = DistributionStatusEnum.findState(distributionStatus); + if (distEnum == null) { + return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND); } - filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS); - return components; + } else { + distEnum = null; } - Set<DistributionStatusEnum> distStatusSet = new HashSet<>(); - distStatusSet.add(distEnum); - Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null); - if (servicesWithDistStatus.isRight()) { // not found == empty list + Either<List<Service>, StorageOperationStatus> components = toscaOperationFacade.getCatalogComponents(ComponentTypeEnum.SERVICE, null, false); + if (components.isRight()) { // not found == empty list return Either.left(new ArrayList<>()); } - return Either.left((List<T>) servicesWithDistStatus.left().value()); + final String categoryName = (String) filters.get(FilterKeyEnum.CATEGORY); + Predicate<Service> servPredicate = Component::isService; + if (StringUtils.isNotBlank(categoryName)) { // primary filter + servPredicate = servPredicate.and( + p -> p.getCategories().parallelStream().map(CategoryDataDefinition::getName).collect(Collectors.toList()).contains(categoryName)); + } + if (distEnum != null) {// secondary filter + servPredicate = servPredicate.and(p -> p.getDistributionStatus() == distEnum); + } + List<Service> serviceList = components.left().value().parallelStream().filter(servPredicate).collect(Collectors.toList()); + + final String version = (String) filters.get(FilterKeyEnum.VERSION); + if (StringUtils.isNotBlank(version)) { + serviceList = filterServicesWithVersion(serviceList, version); + } + final List<String> metadata = (List<String>) filters.get(FilterKeyEnum.METADATA); + if (CollectionUtils.isNotEmpty(metadata)) { + serviceList = filterServicesWithMetadata(serviceList, metadata); + } + return Either.left((List<T>) serviceList); + } + + private List<Service> filterServicesWithMetadata(final List<Service> serviceList, final List<String> metadata) { + Predicate<Service> predicate = Component::isService; + final String regex = "[\\w\\.\\- ]"; + for (final String keyValuePair : metadata) { + final Matcher matcher = Pattern.compile("(" + regex + "+)[:=](" + regex + "+)").matcher(keyValuePair); + if (matcher.find()) { + predicate = predicate.and(service -> matcher.group(2).equals(service.getCategorySpecificMetadata().get(matcher.group(1)))); + } + } + return serviceList.stream().filter(predicate).collect(Collectors.toList()); + } + + private List<Service> filterServicesWithVersion(final List<Service> serviceList, final String version) { + String trim = version.trim(); + final Optional<VersionFilterEnum> versionFilter = VersionFilterEnum.getFilter(trim); + if (versionFilter.isPresent()) { + return versionFilter.get().filter(serviceList, trim); + } + return serviceList; } public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) { @@ -1027,7 +1062,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); } Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade - .getComponentListByUuid(uuid, additionalPropertiesToMatch); + .getComponentListByUuid(uuid, additionalPropertiesToMatch); if (componentsListByUuid.isRight()) { log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed"); ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum); @@ -1059,30 +1094,28 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } 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(); + return URLEncodedUtils.parse(query, StandardCharsets.UTF_8) + .stream().filter(p -> !FilterKeyEnum.getValidFiltersByAssetType(assetType).contains(p.getName())).findAny(); } - private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) { + private List<String> getErrorResponseParams(Map<FilterKeyEnum, Object> filters, ComponentTypeEnum assetType) { List<String> params = new ArrayList<>(); if (1 == filters.size()) { params.add(assetType.getValue().toLowerCase()); params.add(filters.keySet().iterator().next().getName()); - params.add(filters.values().iterator().next()); + params.add((String) filters.values().iterator().next()); } else { params.add(assetType.getValue()); - params.add(filters.get(FilterKeyEnum.SUB_CATEGORY)); - params.add(filters.get(FilterKeyEnum.CATEGORY)); + params.add((String) filters.get(FilterKeyEnum.SUB_CATEGORY)); + params.add((String) filters.get(FilterKeyEnum.CATEGORY)); } return params; } - public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) { - String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY); - String categoryName = filters.get(FilterKeyEnum.CATEGORY); - ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE)); + public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, Object> filters, boolean inTransaction) { + String subCategoryName = (String) filters.get(FilterKeyEnum.SUB_CATEGORY); + String categoryName = (String) filters.get(FilterKeyEnum.CATEGORY); + ResourceTypeEnum resourceType = ResourceTypeEnum.getType((String) filters.get(FilterKeyEnum.RESOURCE_TYPE)); Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null; Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData; if (categoryName != null) { @@ -1095,31 +1128,31 @@ public class ElementBusinessLogic extends BaseBusinessLogic { if (subCategoryName != null) { // primary filter if (categoryName != null) { subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName); - if (!subCategoryData.isPresent()) { + if (subCategoryData.isEmpty()) { return Either.right(StorageOperationStatus.MATCH_NOT_FOUND); } return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction, - resourceType); + resourceType); } return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction, - resourceType); + resourceType); } if (subcategories != null) { return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType); } - return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction); + return fetchComponentMetaDataByResourceType((String) filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction); } private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) { Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation - .getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class); + .getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class); if (categoryResult.isRight()) { return Either.right(categoryResult.right().value()); } CategoryData categoryData = categoryResult.left().value(); Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao - .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), categoryData.getUniqueId(), - GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class); + .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), categoryData.getUniqueId(), + GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class); if (childrenNodes.isRight()) { return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value())); } @@ -1129,7 +1162,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes, String subCategoryName) { Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName() - .equals(subCategoryName); + .equals(subCategoryName); return childNodes.stream().filter(matchName).findAny(); } @@ -1153,10 +1186,11 @@ public class ElementBusinessLogic extends BaseBusinessLogic { ResourceTypeEnum resourceType) { List<T> components = new ArrayList<>(); try { - Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class; + Class<? extends GraphNode> categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class; Map<String, Object> props = new HashMap<>(); props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName)); - Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz); + Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, + (Class<GraphNode>) categoryClazz); if (getCategory.isRight()) { return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND); } @@ -1190,15 +1224,15 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } GraphVertex categoryVertex = categoryVertexById.left().value(); Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao - .getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata); + .getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata); if (componentsVertices.isRight()) { JanusGraphOperationStatus status = componentsVertices.right().value(); log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status); return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status)); } List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value().stream().filter(Objects::nonNull) - .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType())).map(ModelConverter::convertToComponentMetadataDataDefinition) - .collect(Collectors.toList()); + .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType())).map(ModelConverter::convertToComponentMetadataDataDefinition) + .collect(Collectors.toList()); for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) { boolean isHighest = isTrue(component.isHighestVersion()); boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component); @@ -1206,7 +1240,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { boolean isArchived = isTrue(component.isArchived()); if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) { Either<T, StorageOperationStatus> result = toscaOperationFacade - .getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata); + .getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata); if (result.isRight()) { return Either.right(result.right().value()); } @@ -1232,11 +1266,11 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory( - List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) { + List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) { List<T> components = new ArrayList<>(); for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) { Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(), - NodeTypeEnum.Resource, inTransaction, resourceType); + NodeTypeEnum.Resource, inTransaction, resourceType); if (fetched.isRight()) { continue; } @@ -1249,12 +1283,11 @@ public class ElementBusinessLogic extends BaseBusinessLogic { List<Component> components = null; StorageOperationStatus status; Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>(); - Either<List<Component>, StorageOperationStatus> result; try { ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView( - Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue())); + Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue())); Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade - .fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter); + .fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter); if (getResources.isRight()) { status = getResources.right().value(); if (status != StorageOperationStatus.NOT_FOUND) { @@ -1265,12 +1298,11 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } else { components = getResources.left().value(); } - if (!statusWrapper.isEmpty()) { - result = Either.right(statusWrapper.getInnerElement()); + if (statusWrapper.isEmpty()) { + return Either.left(components); } else { - result = Either.left(components); + return Either.right(statusWrapper.getInnerElement()); } - return result; } finally { if (!inTransaction) { janusGraphDao.commit(); @@ -1308,8 +1340,6 @@ public class ElementBusinessLogic extends BaseBusinessLogic { * Fetches default baseType from the template. * * @param categoryName the category name - * - * * @return defaultBaseType mapped to the corresponding category name. */ public String getDefaultBaseType(final String categoryName) { 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 index cb32f152d0..cce2f12343 100644 --- 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 @@ -27,12 +27,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.servers.Server; -import io.swagger.v3.oas.annotations.servers.Servers; import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.tags.Tags; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -51,9 +50,10 @@ 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.collections4.CollectionUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; -import org.openecomp.sdc.be.components.impl.ComponentBusinessLogicProvider; import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; import org.openecomp.sdc.be.components.impl.ElementBusinessLogic; import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; @@ -90,8 +90,8 @@ import org.springframework.stereotype.Controller; */ @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Path("/v1/catalog") -@Tags({@Tag(name = "SDCE-7 APIs")}) -@Servers({@Server(url = "/sdc")}) +@Tag(name = "SDCE-7 APIs") +@Server(url = "/sdc") @Controller public class AssetsDataServlet extends AbstractValidationsServlet { @@ -100,47 +100,67 @@ public class AssetsDataServlet extends AbstractValidationsServlet { private final AssetMetadataConverter assetMetadataConverter; private final ServiceBusinessLogic serviceBusinessLogic; private final ResourceBusinessLogic resourceBusinessLogic; - private final ComponentBusinessLogicProvider componentBusinessLogicProvider; @Context private HttpServletRequest request; @Inject - public AssetsDataServlet(ComponentInstanceBusinessLogic componentInstanceBL, ComponentsUtils componentsUtils, - ServletUtils servletUtils, ResourceImportManager resourceImportManager, ElementBusinessLogic elementBusinessLogic, - AssetMetadataConverter assetMetadataConverter, ComponentBusinessLogicProvider componentBusinessLogicProvider, - ServiceBusinessLogic serviceBusinessLogic, ResourceBusinessLogic resourceBusinessLogic) { + public AssetsDataServlet(ComponentInstanceBusinessLogic componentInstanceBL, ComponentsUtils componentsUtils, ServletUtils servletUtils, + ResourceImportManager resourceImportManager, ElementBusinessLogic elementBusinessLogic, + AssetMetadataConverter assetMetadataConverter, ServiceBusinessLogic serviceBusinessLogic, + ResourceBusinessLogic resourceBusinessLogic) { super(componentInstanceBL, componentsUtils, servletUtils, resourceImportManager); this.elementBusinessLogic = elementBusinessLogic; this.assetMetadataConverter = assetMetadataConverter; this.serviceBusinessLogic = serviceBusinessLogic; this.resourceBusinessLogic = resourceBusinessLogic; - this.componentBusinessLogicProvider = componentBusinessLogicProvider; } @GET @Path("/{assetType}") @Produces(MediaType.APPLICATION_JSON) @Operation(description = "Fetch list of assets", method = "GET", summary = "Returns list of assets", responses = { - @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))), - @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"), - @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"), - @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"), - @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"), - @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")}) + @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))), + @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"), + @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"), + @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"), + @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")}) @PermissionAllowed(AafPermission.PermNames.READ_VALUE) public Response getAssetListExternal( - @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, - @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader, - @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept, - @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, - @Parameter(description = "The requested asset type", schema = @Schema(allowableValues = {"resources", - "services"}), required = true) @PathParam("assetType") final String assetType, - @Parameter(description = "The filter key (resourceType only for resources)", required = false) @QueryParam("category") String category, - @Parameter(description = "The filter key (resourceType only for resources)", required = false) @QueryParam("subCategory") String subCategory, - @Parameter(description = "The filter key (resourceType only for resources)", required = false) @QueryParam("distributionStatus") String distributionStatus, - @Parameter(description = "The filter key (resourceType only for resources)", required = false) @QueryParam("resourceType") String resourceType) - throws IOException { - ResponseFormat responseFormat = null; + @Parameter(description = "X-ECOMP-RequestID header") @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, + @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader, + @Parameter(description = "Determines the format of the body of the response") @HeaderParam(value = Constants.ACCEPT_HEADER) String accept, + @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, + @Parameter(description = "The requested asset type", schema = @Schema(allowableValues = {"resources", "services"}), required = true) @PathParam("assetType") final String assetType, + @Parameter(description = "The category to filter the result set on") @QueryParam("category") String category, + @Parameter(description = "The sub category to filter the result set on. Only applicable when assetType = resources") @QueryParam("subCategory") String subCategory, + @Parameter(description = "The distribution status to filter the result set on") @QueryParam("distributionStatus") String distributionStatus, + @Parameter(description = "The resource type to filter the result set on. Only applicable when assetType = resources") @QueryParam("resourceType") String resourceType, + @Parameter(description = "The version(s) to filter the result set on\n" + + "Syntax: /services?version=(highestMatchingVersionOnly|lessThan|greaterThan|equals)(:=)(value)", + examples = { + @ExampleObject( + name = "An example request to get each service with highest version", + value = "highestMatchingVersionOnly:true"), + @ExampleObject( + name = "An example request to get all services with version less than 2.1", + value = "lessThan:2.1"), + @ExampleObject( + name = "An example request to get all services with version equal 2.0", + value = "equals:2.0"), + @ExampleObject( + name = "An example request to get all services with version greater than 1.1", + value = "greaterThan:1.1")}) + @QueryParam("version") String version, + @Parameter(description = "The keys of the metadata to include in the entries in the result set. Only applicable when assetType = services\n" + + "Only category specific metadata keys are supported\n" + + "Syntax: /services?metadata=<KEY1>(:=)<VALUE1>&metadata=<KEY2>(:=)<VALUE2> ...", + examples = { + @ExampleObject( + name = "An example request to get all services matching following Category Specific Metadata condition 'ETSI Version=3.3.1'", + value = "ETSI Version:3.3.1")}) + @QueryParam("metadata") List<String> metadata) throws IOException { + ResponseFormat responseFormat; String query = request.getQueryString(); String requestURI = request.getRequestURI().endsWith("/") ? removeDuplicateSlashSeparator(request.getRequestURI()) : request.getRequestURI(); String url = request.getMethod() + " " + requestURI; @@ -156,7 +176,7 @@ public class AssetsDataServlet extends AbstractValidationsServlet { return buildErrorResponse(responseFormat); } try { - Map<FilterKeyEnum, String> filters = new EnumMap<>(FilterKeyEnum.class); + Map<FilterKeyEnum, Object> filters = new EnumMap<>(FilterKeyEnum.class); if (category != null) { filters.put(FilterKeyEnum.CATEGORY, category); } @@ -166,6 +186,12 @@ public class AssetsDataServlet extends AbstractValidationsServlet { if (distributionStatus != null) { filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus); } + if (version != null) { + filters.put(FilterKeyEnum.VERSION, version); + } + if (CollectionUtils.isNotEmpty(metadata)) { + filters.put(FilterKeyEnum.METADATA, metadata); + } if (resourceType != null) { ResourceTypeEnum resourceTypeEnum = ResourceTypeEnum.getTypeIgnoreCase(resourceType); if (resourceTypeEnum == null) { @@ -176,8 +202,8 @@ public class AssetsDataServlet extends AbstractValidationsServlet { } filters.put(FilterKeyEnum.RESOURCE_TYPE, resourceTypeEnum.name()); } - Either<List<? extends Component>, ResponseFormat> assetTypeData = elementBusinessLogic - .getFilteredCatalogComponents(assetType, filters, query); + Either<List<? extends Component>, ResponseFormat> assetTypeData + = elementBusinessLogic.getFilteredCatalogComponents(assetType, filters, query); if (assetTypeData.isRight()) { log.debug("getAssetList: Asset Fetching Failed"); responseFormat = assetTypeData.right().value(); @@ -186,7 +212,7 @@ public class AssetsDataServlet extends AbstractValidationsServlet { } else { log.debug("getAssetList: Asset Fetching Success"); Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataConverter - .convertToAssetMetadata(assetTypeData.left().value(), requestURI, false); + .convertToAssetMetadata(assetTypeData.left().value(), requestURI, false); if (resMetadata.isRight()) { log.debug("getAssetList: Asset conversion Failed"); responseFormat = resMetadata.right().value(); @@ -218,22 +244,22 @@ public class AssetsDataServlet extends AbstractValidationsServlet { @Path("/{assetType}/{uuid}/metadata") @Produces(MediaType.APPLICATION_JSON) @Operation(description = "Detailed metadata of asset by uuid", method = "GET", summary = "Returns detailed metadata of an asset by uuid", responses = { - @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))), - @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"), - @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"), - @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"), - @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"), - @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"), - @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")}) + @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))), + @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"), + @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"), + @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"), + @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"), + @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")}) @PermissionAllowed(AafPermission.PermNames.READ_VALUE) public Response getAssetSpecificMetadataByUuidExternal( - @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, - @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader, - @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept, - @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, - @Parameter(description = "The requested asset type", schema = @Schema(allowableValues = {"resources", - "services"}), required = true) @PathParam("assetType") final String assetType, - @Parameter(description = "The requested asset uuid", required = true) @PathParam("uuid") final String uuid) throws IOException { + @Parameter(description = "X-ECOMP-RequestID header") @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, + @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader, + @Parameter(description = "Determines the format of the body of the response") @HeaderParam(value = Constants.ACCEPT_HEADER) String accept, + @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, + @Parameter(description = "The requested asset type", schema = @Schema(allowableValues = {"resources", + "services"}), required = true) @PathParam("assetType") final String assetType, + @Parameter(description = "The requested asset uuid", required = true) @PathParam("uuid") final String uuid) throws IOException { ResponseFormat responseFormat = null; AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA; String requestURI = request.getRequestURI(); @@ -251,7 +277,7 @@ public class AssetsDataServlet extends AbstractValidationsServlet { } try { Either<List<? extends Component>, ResponseFormat> assetTypeData = elementBusinessLogic - .getCatalogComponentsByUuidAndAssetType(assetType, uuid); + .getCatalogComponentsByUuidAndAssetType(assetType, uuid); if (assetTypeData.isRight()) { log.debug("getAssetList: Asset Fetching Failed"); responseFormat = assetTypeData.right().value(); @@ -261,7 +287,7 @@ public class AssetsDataServlet extends AbstractValidationsServlet { resourceCommonInfo.setResourceName(assetTypeData.left().value().iterator().next().getName()); log.debug("getAssetList: Asset Fetching Success"); Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataConverter - .convertToAssetMetadata(assetTypeData.left().value(), requestURI, true); + .convertToAssetMetadata(assetTypeData.left().value(), requestURI, true); if (resMetadata.isRight()) { log.debug("getAssetList: Asset conversion Failed"); responseFormat = resMetadata.right().value(); @@ -301,23 +327,23 @@ public class AssetsDataServlet extends AbstractValidationsServlet { @Path("/{assetType}/{uuid}/toscaModel") @Produces(MediaType.APPLICATION_OCTET_STREAM) @Operation(description = "Fetch assets CSAR", method = "GET", summary = "Returns asset csar", responses = { - @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), - @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), - @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"), - @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"), - @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"), - @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"), - @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"), - @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")}) + @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"), + @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"), + @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"), + @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"), + @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")}) @PermissionAllowed(AafPermission.PermNames.READ_VALUE) public Response getToscaModelExternal( - @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, - @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader, - @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept, - @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, - @Parameter(description = "The requested asset type", schema = @Schema(allowableValues = {"resources", - "services"}), required = true) @PathParam("assetType") final String assetType, - @Parameter(description = "The requested asset uuid", required = true) @PathParam("uuid") final String uuid) { + @Parameter(description = "X-ECOMP-RequestID header") @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId, + @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader, + @Parameter(description = "Determines the format of the body of the response") @HeaderParam(value = Constants.ACCEPT_HEADER) String accept, + @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, + @Parameter(description = "The requested asset type", schema = @Schema(allowableValues = {"resources", + "services"}), required = true) @PathParam("assetType") final String assetType, + @Parameter(description = "The requested asset uuid", required = true) @PathParam("uuid") final String uuid) { String url = request.getRequestURI(); log.debug("Start handle request of {} {}", request.getMethod(), url); ResponseFormat responseFormat = null; 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 index 67533ca656..c4bdd35797 100644 --- 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 @@ -19,6 +19,11 @@ */ package org.openecomp.sdc.be.externalapi.servlet.representation; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter public abstract class AssetMetadata implements IAssetMetadata { private String uuid; @@ -27,103 +32,4 @@ public abstract class AssetMetadata implements IAssetMetadata { 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/ServiceDistributionReqInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceDistributionReqInfo.java index 3abc62147c..109e49e456 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceDistributionReqInfo.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/ServiceDistributionReqInfo.java @@ -19,25 +19,15 @@ */ package org.openecomp.sdc.be.externalapi.servlet.representation; -/** - * Created by chaya on 10/26/2017. - */ +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@AllArgsConstructor public class ServiceDistributionReqInfo { private String workloadContext; - public ServiceDistributionReqInfo() { - } - - public ServiceDistributionReqInfo(String workloadContext) { - this.workloadContext = workloadContext; - } - - public String getWorkloadContext() { - return workloadContext; - } - - public void setWorkloadContext(String workloadContext) { - this.workloadContext = workloadContext; - } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/VersionFilterEnum.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/VersionFilterEnum.java new file mode 100644 index 0000000000..6519f325b6 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/representation/VersionFilterEnum.java @@ -0,0 +1,111 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + * + * + */ + +package org.openecomp.sdc.be.externalapi.servlet.representation; + +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.openecomp.sdc.be.model.Service; + +@Getter +@AllArgsConstructor +public enum VersionFilterEnum { + + EQUALS("equals") { + @Override + public List<Service> filter(final List<Service> serviceList, final String version) { + final Matcher matcher = Pattern.compile("(" + this.getName() + ")" + DELIMITER + "(" + VERSION_REGEX + ")").matcher(version); + if (matcher.find()) { + return serviceList.parallelStream() + .filter(service -> convertToInteger(service.getVersion()).compareTo(convertToInteger(matcher.group(2))) == 0) + .collect(Collectors.toList()); + } + return serviceList; + } + }, + GREATER_THAN("greaterThan") { + @Override + public List<Service> filter(final List<Service> serviceList, final String version) { + final Matcher matcher = Pattern.compile("(" + this.getName() + ")" + DELIMITER + "(" + VERSION_REGEX + ")").matcher(version); + if (matcher.find()) { + return serviceList.parallelStream() + .filter(service -> convertToInteger(service.getVersion()).compareTo(convertToInteger(matcher.group(2))) > 0) + .collect(Collectors.toList()); + } + return serviceList; + } + }, + LESS_THAN("lessThan") { + @Override + public List<Service> filter(final List<Service> serviceList, final String version) { + final Matcher matcher = Pattern.compile("(" + this.getName() + ")" + DELIMITER + "(" + VERSION_REGEX + ")").matcher(version); + if (matcher.find()) { + return serviceList.parallelStream() + .filter(service -> convertToInteger(service.getVersion()).compareTo(convertToInteger(matcher.group(2))) < 0) + .collect(Collectors.toList()); + } + return serviceList; + } + }, + HIGHEST_MATCHING_VERSION_ONLY("highestMatchingVersionOnly") { + @Override + public List<Service> filter(final List<Service> serviceList, final String version) { + final Matcher matcher = Pattern.compile("(" + this.getName() + ")" + DELIMITER + "([Tt][Rr][Uu][Ee])").matcher(version); + if (matcher.find()) { + return serviceList.parallelStream() + .collect(Collectors.groupingBy(Service::getName, + Collectors.maxBy(Comparator.comparingInt(service -> convertToInteger(service.getVersion()))))) + .values().parallelStream().map(Optional::get).collect(Collectors.toList()); + } + return serviceList; + } + }; + + private final String name; + + private static final String VERSION_REGEX = "[0-9]+\\.?[0-9]?"; + private static final String DELIMITER = "[ :=]+"; + + public abstract List<Service> filter(final List<Service> serviceList, final String version); + + public static Optional<VersionFilterEnum> getFilter(final String version) { + final Matcher matcher = Pattern.compile("([a-zA-Z]+)" + DELIMITER).matcher(version); + if (matcher.find()) { + for (final VersionFilterEnum value : VersionFilterEnum.values()) { + if (value.getName().equals(matcher.group(1))) { + return Optional.of(value); + } + } + } + return Optional.empty(); + } + + private static Integer convertToInteger(final String value) { + return (int) (Float.parseFloat(value) * 10); + } + +} |