Initial OpenECOMP SDC commit
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / externalapi / servlet / AssetsDataServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.sdc.be.externalapi.servlet;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.InputStream;
25 import java.nio.charset.StandardCharsets;
26 import java.util.EnumMap;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.function.Predicate;
31
32 import javax.inject.Singleton;
33 import javax.servlet.ServletContext;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.ws.rs.GET;
36 import javax.ws.rs.HeaderParam;
37 import javax.ws.rs.Path;
38 import javax.ws.rs.PathParam;
39 import javax.ws.rs.Produces;
40 import javax.ws.rs.QueryParam;
41 import javax.ws.rs.core.Context;
42 import javax.ws.rs.core.MediaType;
43 import javax.ws.rs.core.Response;
44
45 import org.apache.commons.lang3.tuple.ImmutablePair;
46 import org.apache.http.NameValuePair;
47 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
48 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
49 import org.openecomp.sdc.be.config.BeEcompErrorManager;
50 import org.openecomp.sdc.be.dao.api.ActionStatus;
51 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
52 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
53 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
54 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
55 import org.openecomp.sdc.be.model.Component;
56 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
57 import org.openecomp.sdc.be.servlets.BeGenericServlet;
58 import org.openecomp.sdc.be.servlets.RepresentationUtils;
59 import org.openecomp.sdc.common.api.Constants;
60 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
61 import org.openecomp.sdc.common.util.GeneralUtility;
62 import org.openecomp.sdc.exception.ResponseFormat;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65 import org.springframework.web.context.WebApplicationContext;
66
67 import com.jcabi.aspects.Loggable;
68 import com.wordnik.swagger.annotations.ApiOperation;
69 import com.wordnik.swagger.annotations.ApiParam;
70 import com.wordnik.swagger.annotations.ApiResponse;
71 import com.wordnik.swagger.annotations.ApiResponses;
72
73 import fj.data.Either;
74
75 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
76 @Path("/v1/catalog")
77 @Singleton
78 public class AssetsDataServlet extends BeGenericServlet {
79
80         @Context
81         private HttpServletRequest request;
82
83         private AssetMetadataConverter assetMetadataUtils;
84         private static Logger log = LoggerFactory.getLogger(AssetsDataServlet.class.getName());
85
86         @GET
87         @Path("/{assetType}")
88         @Produces(MediaType.APPLICATION_JSON)
89         @ApiOperation(value = "Fetch list of assets", httpMethod = "GET", notes = "Returns list of assets", response = Response.class)
90         @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), @ApiResponse(code = 401, message = "Authorization required"),
91                         @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Asset not found") })
92         public Response getAssetList(@PathParam("assetType") final String assetType, @QueryParam("category") String category, @QueryParam("subCategory") String subCategory, @QueryParam("distributionStatus") String distributionStatus) {
93
94                 Response response = null;
95                 ResponseFormat responseFormat = null;
96                 String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
97                 String query = request.getQueryString();
98                 String requestURI = request.getRequestURI();
99                 String url = request.getMethod() + " " + requestURI;
100                 log.debug("Start handle request of {}", url);
101                 String serverBaseURL = request.getRequestURL().toString();
102
103                 AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST;
104
105                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
106                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
107                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, query == null ? requestURI : requestURI + "?" + query);
108
109                 // Mandatory
110                 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
111                         log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
112                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
113                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
114                         return buildErrorResponse(responseFormat);
115                 }
116
117                 try {
118                         ServletContext context = request.getSession().getServletContext();
119                         ElementBusinessLogic elementLogic = getElementBL(context);
120
121                         getAssetUtils(context);
122                         Map<FilterKeyEnum, String> filters = new HashMap<FilterKeyEnum, String>();
123
124                         if (category != null) {
125                                 filters.put(FilterKeyEnum.CATEGORY, category);
126                         }
127                         if (subCategory != null) {
128                                 filters.put(FilterKeyEnum.SUB_CATEGORY, subCategory);
129                         }
130                         if (distributionStatus != null) {
131                                 filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus);
132                         }
133
134                         Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getFilteredCatalogComponents(assetType, filters, query);
135
136                         if (assetTypeData.isRight()) {
137                                 log.debug("getAssetList: Asset Fetching Failed");
138                                 responseFormat = assetTypeData.right().value();
139                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
140                                 return buildErrorResponse(responseFormat);
141                         } else {
142                                 log.debug("getAssetList: Asset Fetching Success");
143                                 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), serverBaseURL, false);
144                                 if (resMetadata.isRight()) {
145                                         log.debug("getAssetList: Asset conversion Failed");
146                                         responseFormat = resMetadata.right().value();
147                                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
148                                         return buildErrorResponse(responseFormat);
149                                 }
150                                 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value());
151                                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
152                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
153
154                                 response = buildOkResponse(responseFormat, result);
155                                 return response;
156                         }
157                 } catch (Exception e) {
158                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
159                         log.debug("getAssetList: Fetch list of assets failed with exception", e);
160                         return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
161                 }
162         }
163
164         @GET
165         @Path("/{assetType}/{uuid}/metadata")
166         @Produces(MediaType.APPLICATION_JSON)
167         @ApiOperation(value = "Fetch metadata of asset by uuid", httpMethod = "GET", notes = "Returns metadata of asset", response = Response.class)
168         @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
169                         @ApiResponse(code = 404, message = "Asset not found") })
170         public Response getAssetListByUuid(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @Context final HttpServletRequest request) {
171
172                 Response response = null;
173                 ResponseFormat responseFormat = null;
174                 String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
175                 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA;
176                 String requestURI = request.getRequestURI();
177                 String url = request.getMethod() + " " + requestURI;
178                 log.debug("Start handle request of {}", url);
179                 String serverBaseURL = request.getRequestURL().toString();
180
181                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
182                 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
183                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
184                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI);
185                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
186                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
187
188                 // Mandatory
189                 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
190                         log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
191                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
192                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
193                         return buildErrorResponse(responseFormat);
194                 }
195
196                 try {
197                         ServletContext context = request.getSession().getServletContext();
198                         ElementBusinessLogic elementLogic = getElementBL(context);
199                         getAssetUtils(context);
200
201                         Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid);
202
203                         if (assetTypeData.isRight()) {
204                                 log.debug("getAssetList: Asset Fetching Failed");
205                                 responseFormat = assetTypeData.right().value();
206                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
207
208                                 return buildErrorResponse(responseFormat);
209                         } else {
210                                 log.debug("getAssetList: Asset Fetching Success");
211                                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, assetTypeData.left().value().iterator().next().getName());
212                                 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), serverBaseURL, true);
213                                 if (resMetadata.isRight()) {
214                                         log.debug("getAssetList: Asset conversion Failed");
215                                         responseFormat = resMetadata.right().value();
216                                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
217                                         return buildErrorResponse(responseFormat);
218                                 }
219                                 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value().iterator().next());
220                                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
221                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
222
223                                 response = buildOkResponse(responseFormat, result);
224                                 return response;
225                         }
226                 } catch (Exception e) {
227                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
228                         log.debug("getAssetList: Fetch list of assets failed with exception", e);
229                         return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
230                 }
231         }
232
233         private void getAssetUtils(ServletContext context) {
234                 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
235                 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
236                 assetMetadataUtils = webApplicationContext.getBean(AssetMetadataConverter.class);
237         }
238
239         @GET
240         @Path("/{assetType}/{uuid}/toscaModel")
241         @Produces(MediaType.APPLICATION_OCTET_STREAM)
242         @ApiOperation(value = "Fetch asset csar", httpMethod = "GET", notes = "Returns asset csar", response = Response.class)
243         @ApiResponses(value = { @ApiResponse(code = 200, message = "Asset Model Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
244                         @ApiResponse(code = 404, message = "Asset not found") })
245         public Response getToscaModel(@PathParam("uuid") final String uuid,
246                         @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType,
247                         @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization) {
248
249                 String url = request.getRequestURI();
250                 log.debug("Start handle request of {} {}", request.getMethod(), url);
251                 Response response = null;
252                 ResponseFormat responseFormat = null;
253                 ServletContext context = request.getSession().getServletContext();
254                 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
255                 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_TOSCA_MODEL;
256                 String userId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
257                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
258                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, userId);
259                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, url);
260                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
261                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
262
263                 if (userId == null || userId.isEmpty()) {
264                         log.debug("getToscaModel: Missing X-ECOMP-InstanceID header");
265                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
266                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
267                         return buildErrorResponse(responseFormat);
268                 }
269
270                 try {
271                         ComponentBusinessLogic componentBL = getComponentBL(componentType, context);
272
273                         Either<ImmutablePair<String, byte[]>, ResponseFormat> csarArtifact = componentBL.getToscaModelByComponentUuid(componentType, uuid, additionalParam);
274                         if (csarArtifact.isRight()) {
275                                 responseFormat = csarArtifact.right().value();
276                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
277                                 response = buildErrorResponse(responseFormat);
278                         } else {
279                                 byte[] value = csarArtifact.left().value().getRight();
280                                 InputStream is = new ByteArrayInputStream(value);
281                                 String contenetMD5 = GeneralUtility.calculateMD5ByByteArray(value);
282                                 Map<String, String> headers = new HashMap<>();
283                                 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(csarArtifact.left().value().getLeft()));
284                                 headers.put(Constants.MD5_HEADER, contenetMD5);
285                                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
286                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
287                                 response = buildOkResponse(responseFormat, is, headers);
288                         }
289                         return response;
290
291                 } catch (Exception e) {
292                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get asset tosca model");
293                         log.debug("falied to get asset tosca model", e);
294                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
295                         response = buildErrorResponse(responseFormat);
296                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
297                         return response;
298                 }
299         }
300 }