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 org.apache.commons.lang3.tuple.ImmutablePair;
28 import org.glassfish.jersey.media.multipart.FormDataParam;
29 import org.openecomp.sdc.be.components.impl.*;
30 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
31 import org.openecomp.sdc.be.config.BeEcompErrorManager;
32 import org.openecomp.sdc.be.dao.api.ActionStatus;
33 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
34 import org.openecomp.sdc.be.model.DataTypeDefinition;
35 import org.openecomp.sdc.be.model.GroupTypeDefinition;
36 import org.openecomp.sdc.be.model.PolicyTypeDefinition;
37 import org.openecomp.sdc.be.model.RelationshipTypeDefinition;
38 import org.openecomp.sdc.be.model.User;
39 import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata;
40 import org.openecomp.sdc.common.api.Constants;
41 import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerTwoParam;
42 import org.openecomp.sdc.common.datastructure.Wrapper;
43 import org.openecomp.sdc.common.log.wrappers.Logger;
44 import org.openecomp.sdc.exception.ResponseFormat;
45 import org.springframework.stereotype.Controller;
47 import javax.servlet.http.HttpServletRequest;
49 import javax.ws.rs.core.Context;
50 import javax.ws.rs.core.MediaType;
51 import javax.ws.rs.core.Response;
53 import java.io.IOException;
54 import java.util.List;
57 import java.util.function.Supplier;
58 import java.util.stream.Collectors;
60 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
61 @Path("/v1/catalog/uploadType")
62 @Consumes(MediaType.MULTIPART_FORM_DATA)
63 @Produces(MediaType.APPLICATION_JSON)
64 @Api(value = "Catalog Types Upload")
66 public class TypesUploadServlet extends AbstractValidationsServlet {
67 private static final Logger log = Logger.getLogger(TypesUploadServlet.class);
68 public static final String CREATE = "Create ";
70 private final CapabilityTypeImportManager capabilityTypeImportManager;
71 private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager;
72 private final CategoriesImportManager categoriesImportManager;
73 private final DataTypeImportManager dataTypeImportManager;
74 private final GroupTypeImportManager groupTypeImportManager;
75 private final PolicyTypeImportManager policyTypeImportManager;
76 private final RelationshipTypeImportManager relationshipTypeImportManager;
78 public TypesUploadServlet(CapabilityTypeImportManager capabilityTypeImportManager, InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager, CategoriesImportManager categoriesImportManager, DataTypeImportManager dataTypeImportManager,
79 GroupTypeImportManager groupTypeImportManager, PolicyTypeImportManager policyTypeImportManager,
80 RelationshipTypeImportManager relationshipTypeImportManager) {
81 this.capabilityTypeImportManager = capabilityTypeImportManager;
82 this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager;
83 this.categoriesImportManager = categoriesImportManager;
84 this.dataTypeImportManager = dataTypeImportManager;
85 this.groupTypeImportManager = groupTypeImportManager;
86 this.policyTypeImportManager = policyTypeImportManager;
87 this.relationshipTypeImportManager = relationshipTypeImportManager;
92 @ApiOperation(value = "Create Capability Type from yaml", httpMethod = "POST", notes = "Returns created Capability Type", response = Response.class)
93 @ApiResponses(value = { @ApiResponse(code = 201, message = "Capability Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
94 @ApiResponse(code = 409, message = "Capability Type already exist") })
95 public Response uploadCapabilityType(@ApiParam("FileInputStream") @FormDataParam("capabilityTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
96 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload));
97 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name());
101 @Path("/relationship")
102 @ApiOperation(value = "Create Relationship Type from yaml", httpMethod = "POST",
103 notes = "Returns created Relationship Type", response = Response.class)
104 @ApiResponses(value = {@ApiResponse(code = 201, message = "Relationship Type created"),
105 @ApiResponse(code = 403, message = "Restricted operation"),
106 @ApiResponse(code = 400, message = "Invalid content / Missing content"),
107 @ApiResponse(code = 409, message = "Relationship Type already exist")})
108 public Response uploadRelationshipType(@ApiParam("FileInputStream") @FormDataParam("relationshipTypeZip") File file,
109 @Context final HttpServletRequest request,
110 @HeaderParam("USER_ID") String creator) {
111 return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator,
112 NodeTypeEnum.RelationshipType.getName());
116 @Path("/interfaceLifecycle")
117 @ApiOperation(value = "Create Interface Lyfecycle Type from yaml", httpMethod = "POST", notes = "Returns created Interface Lifecycle Type", response = Response.class)
118 @ApiResponses(value = { @ApiResponse(code = 201, message = "Interface Lifecycle Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
119 @ApiResponse(code = 409, message = "Interface Lifecycle Type already exist") })
120 public Response uploadInterfaceLifecycleType(@ApiParam("FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
121 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload));
122 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types");
127 @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created categories", response = Response.class)
128 @ApiResponses(value = { @ApiResponse(code = 201, message = "Categories created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
129 @ApiResponse(code = 409, message = "Category already exist") })
130 public Response uploadCategories(@ApiParam("FileInputStream") @FormDataParam("categoriesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
131 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload));
132 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories");
137 @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created data types", response = Response.class)
138 @ApiResponses(value = { @ApiResponse(code = 201, message = "Data types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
139 @ApiResponse(code = 409, message = "Data types already exist") })
140 public Response uploadDataTypes(@ApiParam("FileInputStream") @FormDataParam("dataTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
141 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = this::createDataTypes;
142 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.DataType.getName());
147 @ApiOperation(value = "Create GroupTypes from yaml", httpMethod = "POST", notes = "Returns created group types", response = Response.class)
148 @ApiResponses(value = { @ApiResponse(code = 201, message = "group types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
149 @ApiResponse(code = 409, message = "group types already exist") })
150 public Response uploadGroupTypes(@ApiParam("toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
151 @ApiParam("FileInputStream") @FormDataParam("groupTypesZip") File file,
152 @Context final HttpServletRequest request,
153 @HeaderParam("USER_ID") String creator) {
154 Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
155 return uploadTypesWithMetaData(this::createGroupTypes, typesMetadata, file, request, creator, NodeTypeEnum.GroupType.getName());
159 @Path("/policytypes")
160 @ApiOperation(value = "Create PolicyTypes from yaml", httpMethod = "POST", notes = "Returns created policy types", response = Response.class)
161 @ApiResponses(value = { @ApiResponse(code = 201, message = "policy types created"),
162 @ApiResponse(code = 403, message = "Restricted operation"),
163 @ApiResponse(code = 400, message = "Invalid content / Missing content"),
164 @ApiResponse(code = 409, message = "policy types already exist") })
165 public Response uploadPolicyTypes(
166 @ApiParam("toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
167 @ApiParam("FileInputStream") @FormDataParam("policyTypesZip") File file,
168 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
169 Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
170 return uploadTypesWithMetaData(this::createPolicyTypes, typesMetadata, file, request, creator, NodeTypeEnum.PolicyType.getName());
173 private Map<String, ToscaTypeMetadata> getTypesMetadata(String toscaTypesMetaData) {
174 return gson.fromJson(toscaTypesMetaData, new TypeToken<Map<String, ToscaTypeMetadata>>(){}.getType());
177 private Response uploadElementTypeServletLogic(ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod, File file, final HttpServletRequest request, String creator, String elementTypeName) {
179 String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
181 Wrapper<String> yamlStringWrapper = new Wrapper<>();
183 String url = request.getMethod() + " " + request.getRequestURI();
184 log.debug("Start handle request of {}", url);
185 Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
186 if (responseWrapper.isEmpty()) {
187 fillZipContents(yamlStringWrapper, file);
189 if (responseWrapper.isEmpty()) {
190 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement());
192 return responseWrapper.getInnerElement();
193 } catch (Exception e) {
194 log.debug("create {} failed with exception:", elementTypeName, e);
195 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
196 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
200 private Wrapper<Response> doUploadTypeValidations(final HttpServletRequest request, String userId, File file) {
201 Wrapper<Response> responseWrapper = new Wrapper<>();
202 Wrapper<User> userWrapper = new Wrapper<>();
204 String url = request.getMethod() + " " + request.getRequestURI();
205 log.debug("Start handle request of {}", url);
207 validateUserExist(responseWrapper, userWrapper, userId);
209 if (responseWrapper.isEmpty()) {
210 validateUserRole(responseWrapper, userWrapper.getInnerElement());
213 if (responseWrapper.isEmpty()) {
214 validateDataNotNull(responseWrapper, file);
216 return responseWrapper;
219 private Response uploadTypesWithMetaData(ConsumerTwoParam<Wrapper<Response>, ToscaTypeImportData> createElementsMethod, Map<String, ToscaTypeMetadata> typesMetaData, File file, final HttpServletRequest request, String creator, String elementTypeName) {
221 String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
222 Wrapper<String> yamlStringWrapper = new Wrapper<>();
224 Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
225 if (responseWrapper.isEmpty()) {
226 fillZipContents(yamlStringWrapper, file);
228 if (responseWrapper.isEmpty()) {
229 ToscaTypeImportData toscaTypeImportData = new ToscaTypeImportData(yamlStringWrapper.getInnerElement(), typesMetaData);
230 createElementsMethod.accept(responseWrapper, toscaTypeImportData);
232 return responseWrapper.getInnerElement();
233 } catch (Exception e) {
234 log.debug("create {} failed with exception:", elementTypeName, e);
235 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
236 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
240 private <T> void createElementsType(Wrapper<Response> responseWrapper, Supplier<Either<T, ResponseFormat>> elementsCreater) {
241 Either<T, ResponseFormat> eitherResult = elementsCreater.get();
242 if (eitherResult.isRight()) {
243 Response response = buildErrorResponse(eitherResult.right().value());
244 responseWrapper.setInnerElement(response);
247 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), RepresentationUtils.toRepresentation(eitherResult.left().value()));
248 responseWrapper.setInnerElement(response);
249 } catch (Exception e) {
250 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
251 responseWrapper.setInnerElement(response);
252 log.error("#createElementsType - json serialization failed with error: ", e);
258 private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml) {
259 final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> dataTypeImportManager.createDataTypes(dataTypesYml);
260 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.DATA_TYPE_ALREADY_EXIST, NodeTypeEnum.DataType.name());
264 private void createGroupTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData) {
265 final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> groupTypeImportManager.createGroupTypes(toscaTypeImportData);
266 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.GROUP_TYPE_ALREADY_EXIST, NodeTypeEnum.GroupType.name());
270 private void createPolicyTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData) {
271 final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> policyTypeImportManager.createPolicyTypes(toscaTypeImportData);
272 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.POLICY_TYPE_ALREADY_EXIST, NodeTypeEnum.PolicyType.name());
276 private <ElementTypeDefinition> void buildStatusForElementTypeCreate(Wrapper<Response> responseWrapper, Supplier<Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml, ActionStatus alreadyExistStatus, String elementTypeName) {
277 Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> eitherResult = generateElementTypeFromYml.get();
279 if (eitherResult.isRight()) {
280 Response response = buildErrorResponse(eitherResult.right().value());
281 responseWrapper.setInnerElement(response);
283 Object representation;
285 List<ImmutablePair<ElementTypeDefinition, Boolean>> list = eitherResult.left().value();
286 ActionStatus status = ActionStatus.OK;
289 // Group result by the right value - true or false.
290 // I.e., get the number of data types which are new and
292 Map<Boolean, List<ImmutablePair<ElementTypeDefinition, Boolean>>> collect = list.stream().collect(Collectors.groupingBy(ImmutablePair<ElementTypeDefinition, Boolean>::getRight));
293 if (collect != null) {
294 Set<Boolean> keySet = collect.keySet();
295 if (keySet.size() == 1) {
296 Boolean isNew = keySet.iterator().next();
297 if (isNew.booleanValue()) {
298 // all data types created at the first time
299 status = ActionStatus.CREATED;
301 // All data types already exists
303 status = alreadyExistStatus;
308 representation = RepresentationUtils.toRepresentation(eitherResult.left().value());
310 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(status), representation);
311 responseWrapper.setInnerElement(response);
313 } catch (IOException e) {
314 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
315 log.debug("failed to convert {} to json", elementTypeName, e);
316 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
317 responseWrapper.setInnerElement(response);
321 // relationship types
322 private void createRelationshipTypes(Wrapper<Response> responseWrapper, String relationshipTypesYml) {
323 final Supplier<Either<List<ImmutablePair<RelationshipTypeDefinition, Boolean>>, ResponseFormat>>
324 generateElementTypeFromYml =
325 () -> relationshipTypeImportManager.createRelationshipTypes(relationshipTypesYml);
326 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml,
327 ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST, NodeTypeEnum.RelationshipType.name());