Merge "sanity stabilization" into release-1.1.0
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / externalapi / servlet / AssetsDataServlet.java
index 1b8d6fd..b995606 100644 (file)
@@ -22,12 +22,10 @@ package org.openecomp.sdc.be.externalapi.servlet;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Predicate;
 
 import javax.inject.Singleton;
 import javax.servlet.ServletContext;
@@ -43,18 +41,18 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.apache.http.NameValuePair;
 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
+import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
+import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
-import org.openecomp.sdc.be.impl.WebAppContextWrapper;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
-import org.openecomp.sdc.be.servlets.BeGenericServlet;
+import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
 import org.openecomp.sdc.be.servlets.RepresentationUtils;
 import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
@@ -62,43 +60,76 @@ import org.openecomp.sdc.common.util.GeneralUtility;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.web.context.WebApplicationContext;
 
 import com.jcabi.aspects.Loggable;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
 
 import fj.data.Either;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * This Servlet serves external users for retrieving component metadata.
+ * 
+ * @author tgitelman
+ *
+ */
 
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog")
+@Api(value = "Asset Metadata External Servlet", description = "This Servlet serves external users for retrieving component metadata.")
 @Singleton
-public class AssetsDataServlet extends BeGenericServlet {
+public class AssetsDataServlet extends AbstractValidationsServlet {
 
        @Context
        private HttpServletRequest request;
 
-       private AssetMetadataConverter assetMetadataUtils;
        private static Logger log = LoggerFactory.getLogger(AssetsDataServlet.class.getName());
-
+       
+       /**
+        * 
+        * @param requestId
+        * @param instanceIdHeader
+        * @param accept
+        * @param authorization
+        * @param assetType
+        * @param category
+        * @param subCategory
+        * @param distributionStatus
+        * @param resourceType
+        * @return
+        */
        @GET
        @Path("/{assetType}")
        @Produces(MediaType.APPLICATION_JSON)
-       @ApiOperation(value = "Fetch list of assets", httpMethod = "GET", notes = "Returns list of assets", response = Response.class)
-       @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), @ApiResponse(code = 401, message = "Authorization required"),
-                       @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Asset not found") })
-       public Response getAssetList(@PathParam("assetType") final String assetType, @QueryParam("category") String category, @QueryParam("subCategory") String subCategory, @QueryParam("distributionStatus") String distributionStatus) {
+       @ApiOperation(value = "Fetch list of assets", httpMethod = "GET", notes = "Returns list of assets")
+       @ApiResponses(value = {
+                       @ApiResponse(code = 200, message = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", response = AssetMetadata.class, responseContainer="List"),
+                       @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
+                       @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
+                       @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
+                       @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
+                       @ApiResponse(code = 500, message = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")})
+       public Response getAssetListExternal(
+                       @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
+                       @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
+                       @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
+                       @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
+                       @ApiParam(value = "The requested asset type", required = true, allowableValues = "resources, services")@PathParam("assetType") final String assetType, 
+                       @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("category") String category, 
+                       @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("subCategory") String subCategory, 
+                       @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("distributionStatus") String distributionStatus,
+                       @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("resourceType") String resourceType) {
 
                Response response = null;
                ResponseFormat responseFormat = null;
-               String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
                String query = request.getQueryString();
-               String requestURI = request.getRequestURI();
+               String requestURI = request.getRequestURI().endsWith("/")?
+                               removeDuplicateSlashSeparator(request.getRequestURI()): request.getRequestURI();
                String url = request.getMethod() + " " + requestURI;
                log.debug("Start handle request of {}", url);
-               String serverBaseURL = request.getRequestURL().toString();
 
                AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST;
 
@@ -118,8 +149,8 @@ public class AssetsDataServlet extends BeGenericServlet {
                        ServletContext context = request.getSession().getServletContext();
                        ElementBusinessLogic elementLogic = getElementBL(context);
 
-                       getAssetUtils(context);
-                       Map<FilterKeyEnum, String> filters = new HashMap<FilterKeyEnum, String>();
+                       AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
+                       Map<FilterKeyEnum, String> filters = new EnumMap<>(FilterKeyEnum.class);
 
                        if (category != null) {
                                filters.put(FilterKeyEnum.CATEGORY, category);
@@ -130,6 +161,16 @@ public class AssetsDataServlet extends BeGenericServlet {
                        if (distributionStatus != null) {
                                filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus);
                        }
+                       if (resourceType != null) {
+                               ResourceTypeEnum resourceTypeEnum = ResourceTypeEnum.getTypeIgnoreCase(resourceType);
+                               if (resourceTypeEnum == null) {
+                                       log.debug("getAssetList: Asset Fetching Failed. Invalid resource type was received");
+                                       responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
+                                       getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
+                                       return buildErrorResponse(responseFormat);
+                               }
+                               filters.put(FilterKeyEnum.RESOURCE_TYPE, resourceTypeEnum.name());
+                       }
 
                        Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getFilteredCatalogComponents(assetType, filters, query);
 
@@ -140,7 +181,7 @@ public class AssetsDataServlet extends BeGenericServlet {
                                return buildErrorResponse(responseFormat);
                        } else {
                                log.debug("getAssetList: Asset Fetching Success");
-                               Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), serverBaseURL, false);
+                               Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), requestURI, false);
                                if (resMetadata.isRight()) {
                                        log.debug("getAssetList: Asset conversion Failed");
                                        responseFormat = resMetadata.right().value();
@@ -160,30 +201,55 @@ public class AssetsDataServlet extends BeGenericServlet {
                        return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
                }
        }
-
+       
+       /**
+        * 
+        * @param requestId
+        * @param instanceIdHeader
+        * @param accept
+        * @param authorization
+        * @param assetType
+        * @param uuid
+        * @return
+        */
        @GET
        @Path("/{assetType}/{uuid}/metadata")
        @Produces(MediaType.APPLICATION_JSON)
-       @ApiOperation(value = "Fetch metadata of asset by uuid", httpMethod = "GET", notes = "Returns metadata of asset", response = Response.class)
-       @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
-                       @ApiResponse(code = 404, message = "Asset not found") })
-       public Response getAssetListByUuid(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @Context final HttpServletRequest request) {
+       @ApiOperation(value = "Detailed metadata of asset by uuid", httpMethod = "GET", notes = "Returns detailed metadata of an asset by uuid")
+       @ApiResponses(value = {
+                       @ApiResponse(code = 200, message = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", response = AssetMetadata.class, responseContainer="List"),
+                       @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
+                       @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
+                       @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
+                       @ApiResponse(code = 404, message = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
+                       @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
+                       @ApiResponse(code = 500, message = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")})
+       public Response getAssetSpecificMetadataByUuidExternal(
+                       @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
+                       @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
+                       @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
+                       @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
+                       @ApiParam(value = "The requested asset type", required = true, allowableValues = "resources, services")@PathParam("assetType") final String assetType, 
+                       @ApiParam(value = "The requested asset uuid", required = true)@PathParam("uuid") final String uuid) {
 
                Response response = null;
                ResponseFormat responseFormat = null;
-               String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
                AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA;
                String requestURI = request.getRequestURI();
                String url = request.getMethod() + " " + requestURI;
                log.debug("Start handle request of {}", url);
-               String serverBaseURL = request.getRequestURL().toString();
 
-               EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
+               EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<>(AuditingFieldsKeysEnum.class);
                ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
                additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
                additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI);
-               additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
                additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
+               if (componentType == null) {
+                       log.debug("getMetaData: assetType parameter {} is not valid", assetType);
+                       responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
+                       return buildErrorResponse(responseFormat);
+               }
+               additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
 
                // Mandatory
                if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
@@ -196,7 +262,7 @@ public class AssetsDataServlet extends BeGenericServlet {
                try {
                        ServletContext context = request.getSession().getServletContext();
                        ElementBusinessLogic elementLogic = getElementBL(context);
-                       getAssetUtils(context);
+                       AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
 
                        Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid);
 
@@ -209,7 +275,7 @@ public class AssetsDataServlet extends BeGenericServlet {
                        } else {
                                log.debug("getAssetList: Asset Fetching Success");
                                additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, assetTypeData.left().value().iterator().next().getName());
-                               Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), serverBaseURL, true);
+                               Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), requestURI, true);
                                if (resMetadata.isRight()) {
                                        log.debug("getAssetList: Asset conversion Failed");
                                        responseFormat = resMetadata.right().value();
@@ -229,22 +295,36 @@ public class AssetsDataServlet extends BeGenericServlet {
                        return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
                }
        }
-
-       private void getAssetUtils(ServletContext context) {
-               WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
-               WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
-               assetMetadataUtils = webApplicationContext.getBean(AssetMetadataConverter.class);
-       }
-
+       
+       /**
+        * 
+        * @param requestId
+        * @param instanceIdHeader
+        * @param accept
+        * @param authorization
+        * @param assetType
+        * @param uuid
+        * @return
+        */
        @GET
        @Path("/{assetType}/{uuid}/toscaModel")
        @Produces(MediaType.APPLICATION_OCTET_STREAM)
-       @ApiOperation(value = "Fetch asset csar", httpMethod = "GET", notes = "Returns asset csar", response = Response.class)
-       @ApiResponses(value = { @ApiResponse(code = 200, message = "Asset Model Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
-                       @ApiResponse(code = 404, message = "Asset not found") })
-       public Response getToscaModel(@PathParam("uuid") final String uuid,
-                       @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType,
-                       @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization) {
+       @ApiOperation(value = "Fetch assets CSAR", httpMethod = "GET", notes = "Returns asset csar", response = String.class)
+       @ApiResponses(value = {
+                       @ApiResponse(code = 200, message = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", response = String.class),
+                       @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
+                       @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
+                       @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
+                       @ApiResponse(code = 404, message = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
+                       @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
+                       @ApiResponse(code = 500, message = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")})
+       public Response getToscaModelExternal(
+                       @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
+                       @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
+                       @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
+                       @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
+                       @ApiParam(value = "The requested asset type", required = true, allowableValues = "resources, services")@PathParam("assetType") final String assetType, 
+                       @ApiParam(value = "The requested asset uuid", required = true)@PathParam("uuid") final String uuid) {
 
                String url = request.getRequestURI();
                log.debug("Start handle request of {} {}", request.getMethod(), url);
@@ -253,14 +333,20 @@ public class AssetsDataServlet extends BeGenericServlet {
                ServletContext context = request.getSession().getServletContext();
                ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
                AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_TOSCA_MODEL;
-               String userId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
                EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
-               additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, userId);
+               additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
                additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, url);
-               additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
                additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
+               
+               if (componentType == null) {
+                       log.debug("getToscaModel: assetType parameter {} is not valid", assetType);
+                       responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
+                       return buildErrorResponse(responseFormat);
+               }
+               additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
 
-               if (userId == null || userId.isEmpty()) {
+
+               if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
                        log.debug("getToscaModel: Missing X-ECOMP-InstanceID header");
                        responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
                        getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
@@ -278,7 +364,7 @@ public class AssetsDataServlet extends BeGenericServlet {
                        } else {
                                byte[] value = csarArtifact.left().value().getRight();
                                InputStream is = new ByteArrayInputStream(value);
-                               String contenetMD5 = GeneralUtility.calculateMD5ByByteArray(value);
+                               String contenetMD5 = GeneralUtility.calculateMD5Base64EncodedByByteArray(value);
                                Map<String, String> headers = new HashMap<>();
                                headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(csarArtifact.left().value().getLeft()));
                                headers.put(Constants.MD5_HEADER, contenetMD5);
@@ -297,4 +383,11 @@ public class AssetsDataServlet extends BeGenericServlet {
                        return response;
                }
        }
+
+
+       private String removeDuplicateSlashSeparator(String requestUri) {
+               return requestUri.substring(0, requestUri.length()-1);
+       }
+
+
 }