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.servlets;
23 import com.google.gson.reflect.TypeToken;
24 import com.jcabi.aspects.Loggable;
25 import fj.data.Either;
26 import io.swagger.annotations.*;
27 import javax.inject.Inject;
28 import org.apache.commons.lang3.tuple.ImmutablePair;
29 import org.glassfish.jersey.media.multipart.FormDataParam;
30 import org.openecomp.sdc.be.components.impl.*;
31 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
32 import org.openecomp.sdc.be.config.BeEcompErrorManager;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
35 import org.openecomp.sdc.be.impl.ComponentsUtils;
36 import org.openecomp.sdc.be.impl.ServletUtils;
37 import org.openecomp.sdc.be.model.DataTypeDefinition;
38 import org.openecomp.sdc.be.model.GroupTypeDefinition;
39 import org.openecomp.sdc.be.model.PolicyTypeDefinition;
40 import org.openecomp.sdc.be.model.RelationshipTypeDefinition;
41 import org.openecomp.sdc.be.model.User;
42 import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata;
43 import org.openecomp.sdc.be.user.UserBusinessLogic;
44 import org.openecomp.sdc.common.api.Constants;
45 import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerTwoParam;
46 import org.openecomp.sdc.common.datastructure.Wrapper;
47 import org.openecomp.sdc.common.log.wrappers.Logger;
48 import org.openecomp.sdc.exception.ResponseFormat;
49 import org.springframework.stereotype.Controller;
51 import javax.servlet.http.HttpServletRequest;
53 import javax.ws.rs.core.Context;
54 import javax.ws.rs.core.MediaType;
55 import javax.ws.rs.core.Response;
57 import java.io.IOException;
58 import java.util.List;
61 import java.util.function.Supplier;
62 import java.util.stream.Collectors;
64 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
65 @Path("/v1/catalog/uploadType")
66 @Consumes(MediaType.MULTIPART_FORM_DATA)
67 @Produces(MediaType.APPLICATION_JSON)
68 @Api(value = "Catalog Types Upload")
70 public class TypesUploadServlet extends AbstractValidationsServlet {
71 private static final Logger log = Logger.getLogger(TypesUploadServlet.class);
72 public static final String CREATE = "Create ";
74 private final CapabilityTypeImportManager capabilityTypeImportManager;
75 private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager;
76 private final CategoriesImportManager categoriesImportManager;
77 private final DataTypeImportManager dataTypeImportManager;
78 private final GroupTypeImportManager groupTypeImportManager;
79 private final PolicyTypeImportManager policyTypeImportManager;
80 private final RelationshipTypeImportManager relationshipTypeImportManager;
83 public TypesUploadServlet(UserBusinessLogic userBusinessLogic,
84 ComponentInstanceBusinessLogic componentInstanceBL,
85 ComponentsUtils componentsUtils, ServletUtils servletUtils,
86 ResourceImportManager resourceImportManager,
87 CapabilityTypeImportManager capabilityTypeImportManager,
88 InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager,
89 CategoriesImportManager categoriesImportManager,
90 DataTypeImportManager dataTypeImportManager,
91 GroupTypeImportManager groupTypeImportManager,
92 PolicyTypeImportManager policyTypeImportManager,
93 RelationshipTypeImportManager relationshipTypeImportManager) {
94 super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
95 this.capabilityTypeImportManager = capabilityTypeImportManager;
96 this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager;
97 this.categoriesImportManager = categoriesImportManager;
98 this.dataTypeImportManager = dataTypeImportManager;
99 this.groupTypeImportManager = groupTypeImportManager;
100 this.policyTypeImportManager = policyTypeImportManager;
101 this.relationshipTypeImportManager = relationshipTypeImportManager;
106 @ApiOperation(value = "Create Capability Type from yaml", httpMethod = "POST", notes = "Returns created Capability Type", response = Response.class)
107 @ApiResponses(value = { @ApiResponse(code = 201, message = "Capability Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
108 @ApiResponse(code = 409, message = "Capability Type already exist") })
109 public Response uploadCapabilityType(@ApiParam("FileInputStream") @FormDataParam("capabilityTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
110 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload));
111 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name());
115 @Path("/relationship")
116 @ApiOperation(value = "Create Relationship Type from yaml", httpMethod = "POST",
117 notes = "Returns created Relationship Type", response = Response.class)
118 @ApiResponses(value = {@ApiResponse(code = 201, message = "Relationship Type created"),
119 @ApiResponse(code = 403, message = "Restricted operation"),
120 @ApiResponse(code = 400, message = "Invalid content / Missing content"),
121 @ApiResponse(code = 409, message = "Relationship Type already exist")})
122 public Response uploadRelationshipType(@ApiParam("FileInputStream") @FormDataParam("relationshipTypeZip") File file,
123 @Context final HttpServletRequest request,
124 @HeaderParam("USER_ID") String creator) {
125 return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator,
126 NodeTypeEnum.RelationshipType.getName());
130 @Path("/interfaceLifecycle")
131 @ApiOperation(value = "Create Interface Lyfecycle Type from yaml", httpMethod = "POST", notes = "Returns created Interface Lifecycle Type", response = Response.class)
132 @ApiResponses(value = { @ApiResponse(code = 201, message = "Interface Lifecycle Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
133 @ApiResponse(code = 409, message = "Interface Lifecycle Type already exist") })
134 public Response uploadInterfaceLifecycleType(@ApiParam("FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
135 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload));
136 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types");
141 @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created categories", response = Response.class)
142 @ApiResponses(value = { @ApiResponse(code = 201, message = "Categories created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
143 @ApiResponse(code = 409, message = "Category already exist") })
144 public Response uploadCategories(@ApiParam("FileInputStream") @FormDataParam("categoriesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
145 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload));
146 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories");
151 @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created data types", response = Response.class)
152 @ApiResponses(value = { @ApiResponse(code = 201, message = "Data types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
153 @ApiResponse(code = 409, message = "Data types already exist") })
154 public Response uploadDataTypes(@ApiParam("FileInputStream") @FormDataParam("dataTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
155 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = this::createDataTypes;
156 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.DataType.getName());
161 @ApiOperation(value = "Create GroupTypes from yaml", httpMethod = "POST", notes = "Returns created group types", response = Response.class)
162 @ApiResponses(value = { @ApiResponse(code = 201, message = "group types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
163 @ApiResponse(code = 409, message = "group types already exist") })
164 public Response uploadGroupTypes(@ApiParam("toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
165 @ApiParam("FileInputStream") @FormDataParam("groupTypesZip") File file,
166 @Context final HttpServletRequest request,
167 @HeaderParam("USER_ID") String creator) {
168 Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
169 return uploadTypesWithMetaData(this::createGroupTypes, typesMetadata, file, request, creator, NodeTypeEnum.GroupType.getName());
173 @Path("/policytypes")
174 @ApiOperation(value = "Create PolicyTypes from yaml", httpMethod = "POST", notes = "Returns created policy types", response = Response.class)
175 @ApiResponses(value = { @ApiResponse(code = 201, message = "policy types created"),
176 @ApiResponse(code = 403, message = "Restricted operation"),
177 @ApiResponse(code = 400, message = "Invalid content / Missing content"),
178 @ApiResponse(code = 409, message = "policy types already exist") })
179 public Response uploadPolicyTypes(
180 @ApiParam("toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
181 @ApiParam("FileInputStream") @FormDataParam("policyTypesZip") File file,
182 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
183 Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
184 return uploadTypesWithMetaData(this::createPolicyTypes, typesMetadata, file, request, creator, NodeTypeEnum.PolicyType.getName());
187 private Map<String, ToscaTypeMetadata> getTypesMetadata(String toscaTypesMetaData) {
188 return gson.fromJson(toscaTypesMetaData, new TypeToken<Map<String, ToscaTypeMetadata>>(){}.getType());
191 private Response uploadElementTypeServletLogic(ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod, File file, final HttpServletRequest request, String creator, String elementTypeName) {
193 String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
195 Wrapper<String> yamlStringWrapper = new Wrapper<>();
197 String url = request.getMethod() + " " + request.getRequestURI();
198 log.debug("Start handle request of {}", url);
199 Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
200 if (responseWrapper.isEmpty()) {
201 fillZipContents(yamlStringWrapper, file);
203 if (responseWrapper.isEmpty()) {
204 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement());
206 return responseWrapper.getInnerElement();
207 } catch (Exception e) {
208 log.debug("create {} failed with exception:", elementTypeName, e);
209 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
210 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
214 private Wrapper<Response> doUploadTypeValidations(final HttpServletRequest request, String userId, File file) {
215 Wrapper<Response> responseWrapper = new Wrapper<>();
216 Wrapper<User> userWrapper = new Wrapper<>();
218 String url = request.getMethod() + " " + request.getRequestURI();
219 log.debug("Start handle request of {}", url);
221 validateUserExist(responseWrapper, userWrapper, userId);
223 if (responseWrapper.isEmpty()) {
224 validateUserRole(responseWrapper, userWrapper.getInnerElement());
227 if (responseWrapper.isEmpty()) {
228 validateDataNotNull(responseWrapper, file);
230 return responseWrapper;
233 private Response uploadTypesWithMetaData(ConsumerTwoParam<Wrapper<Response>, ToscaTypeImportData> createElementsMethod, Map<String, ToscaTypeMetadata> typesMetaData, File file, final HttpServletRequest request, String creator, String elementTypeName) {
235 String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
236 Wrapper<String> yamlStringWrapper = new Wrapper<>();
238 Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
239 if (responseWrapper.isEmpty()) {
240 fillZipContents(yamlStringWrapper, file);
242 if (responseWrapper.isEmpty()) {
243 ToscaTypeImportData toscaTypeImportData = new ToscaTypeImportData(yamlStringWrapper.getInnerElement(), typesMetaData);
244 createElementsMethod.accept(responseWrapper, toscaTypeImportData);
246 return responseWrapper.getInnerElement();
247 } catch (Exception e) {
248 log.debug("create {} failed with exception:", elementTypeName, e);
249 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
250 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
254 private <T> void createElementsType(Wrapper<Response> responseWrapper, Supplier<Either<T, ResponseFormat>> elementsCreater) {
255 Either<T, ResponseFormat> eitherResult = elementsCreater.get();
256 if (eitherResult.isRight()) {
257 Response response = buildErrorResponse(eitherResult.right().value());
258 responseWrapper.setInnerElement(response);
261 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), RepresentationUtils.toRepresentation(eitherResult.left().value()));
262 responseWrapper.setInnerElement(response);
263 } catch (Exception e) {
264 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
265 responseWrapper.setInnerElement(response);
266 log.error("#createElementsType - json serialization failed with error: ", e);
272 private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml) {
273 final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> dataTypeImportManager.createDataTypes(dataTypesYml);
274 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.DATA_TYPE_ALREADY_EXIST, NodeTypeEnum.DataType.name());
278 private void createGroupTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData) {
279 final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> groupTypeImportManager.createGroupTypes(toscaTypeImportData);
280 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.GROUP_TYPE_ALREADY_EXIST, NodeTypeEnum.GroupType.name());
284 private void createPolicyTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData) {
285 final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> policyTypeImportManager.createPolicyTypes(toscaTypeImportData);
286 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.POLICY_TYPE_ALREADY_EXIST, NodeTypeEnum.PolicyType.name());
290 private <ElementTypeDefinition> void buildStatusForElementTypeCreate(Wrapper<Response> responseWrapper, Supplier<Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml, ActionStatus alreadyExistStatus, String elementTypeName) {
291 Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> eitherResult = generateElementTypeFromYml.get();
293 if (eitherResult.isRight()) {
294 Response response = buildErrorResponse(eitherResult.right().value());
295 responseWrapper.setInnerElement(response);
297 Object representation;
299 List<ImmutablePair<ElementTypeDefinition, Boolean>> list = eitherResult.left().value();
300 ActionStatus status = ActionStatus.OK;
303 // Group result by the right value - true or false.
304 // I.e., get the number of data types which are new and
306 Map<Boolean, List<ImmutablePair<ElementTypeDefinition, Boolean>>> collect = list.stream().collect(Collectors.groupingBy(ImmutablePair<ElementTypeDefinition, Boolean>::getRight));
307 if (collect != null) {
308 Set<Boolean> keySet = collect.keySet();
309 if (keySet.size() == 1) {
310 Boolean isNew = keySet.iterator().next();
311 if (isNew.booleanValue()) {
312 // all data types created at the first time
313 status = ActionStatus.CREATED;
315 // All data types already exists
317 status = alreadyExistStatus;
322 representation = RepresentationUtils.toRepresentation(eitherResult.left().value());
324 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(status), representation);
325 responseWrapper.setInnerElement(response);
327 } catch (IOException e) {
328 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
329 log.debug("failed to convert {} to json", elementTypeName, e);
330 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
331 responseWrapper.setInnerElement(response);
335 // relationship types
336 private void createRelationshipTypes(Wrapper<Response> responseWrapper, String relationshipTypesYml) {
337 final Supplier<Either<List<ImmutablePair<RelationshipTypeDefinition, Boolean>>, ResponseFormat>>
338 generateElementTypeFromYml =
339 () -> relationshipTypeImportManager.createRelationshipTypes(relationshipTypesYml);
340 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml,
341 ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST, NodeTypeEnum.RelationshipType.name());