2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.externalapi.servlet;
23 import com.jcabi.aspects.Loggable;
24 import fj.data.Either;
25 import io.swagger.v3.oas.annotations.OpenAPIDefinition;
26 import io.swagger.v3.oas.annotations.Operation;
27 import io.swagger.v3.oas.annotations.Parameter;
28 import io.swagger.v3.oas.annotations.info.Info;
29 import io.swagger.v3.oas.annotations.media.ArraySchema;
30 import io.swagger.v3.oas.annotations.media.Content;
31 import io.swagger.v3.oas.annotations.media.Schema;
32 import io.swagger.v3.oas.annotations.responses.ApiResponse;
33 import io.swagger.v3.oas.annotations.responses.ApiResponses;
34 import org.apache.commons.lang3.tuple.ImmutablePair;
35 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
36 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogicProvider;
37 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
38 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
39 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
40 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
41 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
42 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
43 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
44 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
45 import org.openecomp.sdc.be.config.BeEcompErrorManager;
46 import org.openecomp.sdc.be.dao.api.ActionStatus;
47 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
48 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
49 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
50 import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
51 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
52 import org.openecomp.sdc.be.impl.ComponentsUtils;
53 import org.openecomp.sdc.be.impl.ServletUtils;
54 import org.openecomp.sdc.be.model.Component;
55 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
56 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
57 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo;
58 import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
59 import org.openecomp.sdc.be.servlets.RepresentationUtils;
60 import org.openecomp.sdc.be.user.UserBusinessLogic;
61 import org.openecomp.sdc.common.api.Constants;
62 import org.openecomp.sdc.common.log.wrappers.Logger;
63 import org.openecomp.sdc.common.util.GeneralUtility;
64 import org.openecomp.sdc.exception.ResponseFormat;
65 import org.springframework.stereotype.Controller;
67 import javax.inject.Inject;
68 import javax.servlet.http.HttpServletRequest;
69 import javax.ws.rs.GET;
70 import javax.ws.rs.HeaderParam;
71 import javax.ws.rs.Path;
72 import javax.ws.rs.PathParam;
73 import javax.ws.rs.Produces;
74 import javax.ws.rs.QueryParam;
75 import javax.ws.rs.core.Context;
76 import javax.ws.rs.core.MediaType;
77 import javax.ws.rs.core.Response;
78 import java.io.ByteArrayInputStream;
79 import java.io.IOException;
80 import java.io.InputStream;
81 import java.util.EnumMap;
82 import java.util.HashMap;
83 import java.util.List;
86 import static org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum.RESOURCE;
89 * This Servlet serves external users for retrieving component metadata.
95 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
97 // for retrieving component metadata.")
98 @OpenAPIDefinition(info = @Info(title = "Asset Metadata External Servlet",
99 description = "This Servlet serves external users for retrieving component metadata."))
101 public class AssetsDataServlet extends AbstractValidationsServlet {
104 private HttpServletRequest request;
106 private static final Logger log = Logger.getLogger(AssetsDataServlet.class);
108 private final ElementBusinessLogic elementBusinessLogic;
109 private final AssetMetadataConverter assetMetadataConverter;
110 private final ServiceBusinessLogic serviceBusinessLogic;
111 private final ResourceBusinessLogic resourceBusinessLogic;
112 private final ComponentBusinessLogicProvider componentBusinessLogicProvider;
115 public AssetsDataServlet(UserBusinessLogic userBusinessLogic, ComponentInstanceBusinessLogic componentInstanceBL,
116 ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager,
117 ElementBusinessLogic elementBusinessLogic, AssetMetadataConverter assetMetadataConverter,
118 ComponentBusinessLogicProvider componentBusinessLogicProvider, ServiceBusinessLogic serviceBusinessLogic, ResourceBusinessLogic resourceBusinessLogic) {
119 super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
120 this.elementBusinessLogic = elementBusinessLogic;
121 this.assetMetadataConverter = assetMetadataConverter;
122 this.serviceBusinessLogic = serviceBusinessLogic;
123 this.resourceBusinessLogic = resourceBusinessLogic;
124 this.componentBusinessLogicProvider = componentBusinessLogicProvider;
128 @Path("/{assetType}")
129 @Produces(MediaType.APPLICATION_JSON)
130 @Operation(description = "Fetch list of assets", method = "GET", summary = "Returns list of assets")
131 @ApiResponses(value = {
132 @ApiResponse(responseCode = "200",
133 description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned",
134 content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))),
135 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
136 @ApiResponse(responseCode = "401",
137 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
138 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
139 @ApiResponse(responseCode = "405",
140 description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
141 @ApiResponse(responseCode = "500",
142 description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")})
143 @PermissionAllowed(AafPermission.PermNames.READ_VALUE)
144 public Response getAssetListExternal(
145 @Parameter(description = "X-ECOMP-RequestID header",
146 required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
147 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(
148 value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
149 @Parameter(description = "Determines the format of the body of the response",
150 required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
151 @Parameter(description = "The username and password",
152 required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
153 @Parameter(description = "The requested asset type",schema = @Schema(allowableValues = {"resources", "services"}),
154 required = true) @PathParam("assetType") final String assetType,
155 @Parameter(description = "The filter key (resourceType only for resources)",
156 required = false) @QueryParam("category") String category,
157 @Parameter(description = "The filter key (resourceType only for resources)",
158 required = false) @QueryParam("subCategory") String subCategory,
159 @Parameter(description = "The filter key (resourceType only for resources)",
160 required = false) @QueryParam("distributionStatus") String distributionStatus,
161 @Parameter(description = "The filter key (resourceType only for resources)",
162 required = false) @QueryParam("resourceType") String resourceType) throws IOException {
164 Response response = null;
165 ResponseFormat responseFormat = null;
166 String query = request.getQueryString();
167 String requestURI = request.getRequestURI().endsWith("/")?
168 removeDuplicateSlashSeparator(request.getRequestURI()): request.getRequestURI();
169 String url = request.getMethod() + " " + requestURI;
170 log.debug("Start handle request of {}", url);
172 AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST;
174 String resourceUrl = query == null ? requestURI : requestURI + "?" + query;
175 DistributionData distributionData = new DistributionData(instanceIdHeader, resourceUrl);
178 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
179 log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
180 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
181 getComponentsUtils().auditExternalGetAssetList(responseFormat, auditingActionEnum, distributionData, requestId);
182 return buildErrorResponse(responseFormat);
186 Map<FilterKeyEnum, String> filters = new EnumMap<>(FilterKeyEnum.class);
188 if (category != null) {
189 filters.put(FilterKeyEnum.CATEGORY, category);
191 if (subCategory != null) {
192 filters.put(FilterKeyEnum.SUB_CATEGORY, subCategory);
194 if (distributionStatus != null) {
195 filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus);
197 if (resourceType != null) {
198 ResourceTypeEnum resourceTypeEnum = ResourceTypeEnum.getTypeIgnoreCase(resourceType);
199 if (resourceTypeEnum == null) {
200 log.debug("getAssetList: Asset Fetching Failed. Invalid resource type was received");
201 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
202 getComponentsUtils().auditExternalGetAssetList(responseFormat, auditingActionEnum, distributionData, requestId);
203 return buildErrorResponse(responseFormat);
205 filters.put(FilterKeyEnum.RESOURCE_TYPE, resourceTypeEnum.name());
208 Either<List<? extends Component>, ResponseFormat> assetTypeData = elementBusinessLogic.getFilteredCatalogComponents(assetType, filters, query);
210 if (assetTypeData.isRight()) {
211 log.debug("getAssetList: Asset Fetching Failed");
212 responseFormat = assetTypeData.right().value();
213 getComponentsUtils().auditExternalGetAssetList(responseFormat, auditingActionEnum, distributionData, requestId);
214 return buildErrorResponse(responseFormat);
216 log.debug("getAssetList: Asset Fetching Success");
217 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataConverter.convertToAssetMetadata(assetTypeData.left().value(), requestURI, false);
218 if (resMetadata.isRight()) {
219 log.debug("getAssetList: Asset conversion Failed");
220 responseFormat = resMetadata.right().value();
221 getComponentsUtils().auditExternalGetAssetList(responseFormat, auditingActionEnum, distributionData, requestId);
222 return buildErrorResponse(responseFormat);
224 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value());
225 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
226 getComponentsUtils().auditExternalGetAssetList(responseFormat, auditingActionEnum, distributionData, requestId);
228 response = buildOkResponse(responseFormat, result);
231 } catch (Exception e) {
232 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
233 log.debug("getAssetList: Fetch list of assets failed with exception", e);
241 * @param instanceIdHeader
243 * @param authorization
249 @Path("/{assetType}/{uuid}/metadata")
250 @Produces(MediaType.APPLICATION_JSON)
251 @Operation(description = "Detailed metadata of asset by uuid", method = "GET",
252 summary = "Returns detailed metadata of an asset by uuid")
253 @ApiResponses(value = {
254 @ApiResponse(responseCode = "200",
255 description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned",
256 content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))),
257 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
258 @ApiResponse(responseCode = "401",
259 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
260 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
261 @ApiResponse(responseCode = "404",
262 description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
263 @ApiResponse(responseCode = "405",
264 description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
265 @ApiResponse(responseCode = "500",
266 description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")})
267 @PermissionAllowed(AafPermission.PermNames.READ_VALUE)
268 public Response getAssetSpecificMetadataByUuidExternal(
269 @Parameter(description = "X-ECOMP-RequestID header",
270 required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
271 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(
272 value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
273 @Parameter(description = "Determines the format of the body of the response",
274 required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
275 @Parameter(description = "The username and password",
276 required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
277 @Parameter(description = "The requested asset type",schema = @Schema(allowableValues = {"resources", "services"}),
278 required = true) @PathParam("assetType") final String assetType,
279 @Parameter(description = "The requested asset uuid",
280 required = true) @PathParam("uuid") final String uuid) throws IOException {
282 Response response = null;
283 ResponseFormat responseFormat = null;
284 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA;
285 String requestURI = request.getRequestURI();
286 String url = request.getMethod() + " " + requestURI;
287 log.debug("Start handle request of {}", url);
289 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
290 ResourceCommonInfo resourceCommonInfo = new ResourceCommonInfo(componentType.getValue());
291 DistributionData distributionData = new DistributionData(instanceIdHeader, requestURI);
293 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
294 log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
295 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
296 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
297 resourceCommonInfo, requestId, uuid);
298 return buildErrorResponse(responseFormat);
303 Either<List<? extends Component>, ResponseFormat> assetTypeData = elementBusinessLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid);
305 if (assetTypeData.isRight()) {
306 log.debug("getAssetList: Asset Fetching Failed");
307 responseFormat = assetTypeData.right().value();
308 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
309 resourceCommonInfo, requestId, uuid);
311 return buildErrorResponse(responseFormat);
313 resourceCommonInfo.setResourceName(assetTypeData.left().value().iterator().next().getName());
314 log.debug("getAssetList: Asset Fetching Success");
315 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataConverter.convertToAssetMetadata(assetTypeData.left().value(), requestURI, true);
316 if (resMetadata.isRight()) {
317 log.debug("getAssetList: Asset conversion Failed");
318 responseFormat = resMetadata.right().value();
320 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
321 resourceCommonInfo, requestId, uuid);
322 return buildErrorResponse(responseFormat);
324 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value().iterator().next());
325 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
326 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
327 resourceCommonInfo, requestId, uuid);
329 response = buildOkResponse(responseFormat, result);
332 } catch (Exception e) {
333 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
334 log.debug("getAssetList: Fetch list of assets failed with exception", e);
339 private ComponentBusinessLogic getComponentBLByType(ComponentTypeEnum componentTypeEnum) {
340 if(componentTypeEnum.equals(RESOURCE)) {
341 return resourceBusinessLogic;
343 // Implementation is the same for any ComponentBusinessLogic
344 return serviceBusinessLogic;
351 * @param instanceIdHeader
353 * @param authorization
360 @Path("/{assetType}/{uuid}/toscaModel")
361 @Produces(MediaType.APPLICATION_OCTET_STREAM)
362 @Operation(description = "Fetch assets CSAR", method = "GET", summary = "Returns asset csar",
363 responses = @ApiResponse(
364 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))))
365 @ApiResponses(value = {
366 @ApiResponse(responseCode = "200",
367 description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned",
368 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
369 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
370 @ApiResponse(responseCode = "401",
371 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
372 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
373 @ApiResponse(responseCode = "404",
374 description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
375 @ApiResponse(responseCode = "405",
376 description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
377 @ApiResponse(responseCode = "500",
378 description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000")})
379 @PermissionAllowed(AafPermission.PermNames.READ_VALUE)
380 public Response getToscaModelExternal(
381 @Parameter(description = "X-ECOMP-RequestID header",
382 required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
383 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(
384 value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
385 @Parameter(description = "Determines the format of the body of the response",
386 required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
387 @Parameter(description = "The username and password",
388 required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
389 @Parameter(description = "The requested asset type",schema = @Schema(allowableValues = {"resources", "services"}),
390 required = true) @PathParam("assetType") final String assetType,
391 @Parameter(description = "The requested asset uuid",
392 required = true) @PathParam("uuid") final String uuid) {
394 String url = request.getRequestURI();
395 log.debug("Start handle request of {} {}", request.getMethod(), url);
396 Response response = null;
397 ResponseFormat responseFormat = null;
398 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
399 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_TOSCA_MODEL;
401 ResourceCommonInfo resourceCommonInfo = new ResourceCommonInfo(componentType.getValue());
402 DistributionData distributionData = new DistributionData(instanceIdHeader, url);
404 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
405 log.debug("getToscaModel: Missing X-ECOMP-InstanceID header");
406 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
407 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
408 resourceCommonInfo, requestId, uuid);
409 return buildErrorResponse(responseFormat);
413 ComponentBusinessLogic componentBusinessLogic = getComponentBLByType(componentType);
414 ImmutablePair<String, byte[]> csarArtifact = componentBusinessLogic.getToscaModelByComponentUuid(componentType, uuid, resourceCommonInfo);
415 byte[] value = csarArtifact.getRight();
416 InputStream is = new ByteArrayInputStream(value);
417 String contenetMD5 = GeneralUtility.calculateMD5Base64EncodedByByteArray(value);
418 Map<String, String> headers = new HashMap<>();
419 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(csarArtifact.getLeft()));
420 headers.put(Constants.MD5_HEADER, contenetMD5);
421 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
422 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
423 resourceCommonInfo, requestId, uuid);
424 response = buildOkResponse(responseFormat, is, headers);
427 } catch (ComponentException e) {
428 responseFormat = e.getResponseFormat();
429 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
430 resourceCommonInfo, requestId, uuid);
431 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get asset tosca model");
432 log.debug("failed to get asset tosca model", e);
433 response = buildErrorResponse(responseFormat);
434 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData,
435 resourceCommonInfo, requestId, uuid);
441 private String removeDuplicateSlashSeparator(String requestUri) {
442 return requestUri.substring(0, requestUri.length()-1);