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.v3.oas.annotations.Operation;
27 import io.swagger.v3.oas.annotations.Parameter;
28 import io.swagger.v3.oas.annotations.media.ArraySchema;
29 import io.swagger.v3.oas.annotations.media.Content;
30 import io.swagger.v3.oas.annotations.media.Schema;
31 import io.swagger.v3.oas.annotations.responses.ApiResponse;
32 import io.swagger.v3.oas.annotations.servers.Server;
33 import io.swagger.v3.oas.annotations.servers.Servers;
34 import io.swagger.v3.oas.annotations.tags.Tag;
35 import io.swagger.v3.oas.annotations.tags.Tags;
36 import org.apache.commons.lang3.tuple.ImmutablePair;
37 import org.glassfish.jersey.media.multipart.FormDataParam;
38 import org.openecomp.sdc.be.components.impl.CapabilityTypeImportManager;
39 import org.openecomp.sdc.be.components.impl.CategoriesImportManager;
40 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
41 import org.openecomp.sdc.be.components.impl.DataTypeImportManager;
42 import org.openecomp.sdc.be.components.impl.GroupTypeImportManager;
43 import org.openecomp.sdc.be.components.impl.InterfaceLifecycleTypeImportManager;
44 import org.openecomp.sdc.be.components.impl.PolicyTypeImportManager;
45 import org.openecomp.sdc.be.components.impl.RelationshipTypeImportManager;
46 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
47 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
48 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
49 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
50 import org.openecomp.sdc.be.config.BeEcompErrorManager;
51 import org.openecomp.sdc.be.dao.api.ActionStatus;
52 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
53 import org.openecomp.sdc.be.impl.ComponentsUtils;
54 import org.openecomp.sdc.be.impl.ServletUtils;
55 import org.openecomp.sdc.be.model.DataTypeDefinition;
56 import org.openecomp.sdc.be.model.GroupTypeDefinition;
57 import org.openecomp.sdc.be.model.PolicyTypeDefinition;
58 import org.openecomp.sdc.be.model.RelationshipTypeDefinition;
59 import org.openecomp.sdc.be.model.User;
60 import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata;
61 import org.openecomp.sdc.be.user.UserBusinessLogic;
62 import org.openecomp.sdc.common.api.Constants;
63 import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerTwoParam;
64 import org.openecomp.sdc.common.datastructure.Wrapper;
65 import org.openecomp.sdc.common.log.wrappers.Logger;
66 import org.openecomp.sdc.exception.ResponseFormat;
67 import org.springframework.stereotype.Controller;
69 import javax.inject.Inject;
70 import javax.servlet.http.HttpServletRequest;
71 import javax.ws.rs.Consumes;
72 import javax.ws.rs.HeaderParam;
73 import javax.ws.rs.POST;
74 import javax.ws.rs.Path;
75 import javax.ws.rs.Produces;
76 import javax.ws.rs.core.Context;
77 import javax.ws.rs.core.MediaType;
78 import javax.ws.rs.core.Response;
80 import java.io.IOException;
81 import java.util.List;
84 import java.util.function.Supplier;
85 import java.util.stream.Collectors;
87 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
88 @Path("/v1/catalog/uploadType")
89 @Consumes(MediaType.MULTIPART_FORM_DATA)
90 @Produces(MediaType.APPLICATION_JSON)
91 @Tags({@Tag(name = "SDCE-2 APIs")})
92 @Servers({@Server(url = "/sdc2/rest")})
94 public class TypesUploadServlet extends AbstractValidationsServlet {
95 private static final Logger log = Logger.getLogger(TypesUploadServlet.class);
96 public static final String CREATE = "Create ";
98 private final CapabilityTypeImportManager capabilityTypeImportManager;
99 private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager;
100 private final CategoriesImportManager categoriesImportManager;
101 private final DataTypeImportManager dataTypeImportManager;
102 private final GroupTypeImportManager groupTypeImportManager;
103 private final PolicyTypeImportManager policyTypeImportManager;
104 private final RelationshipTypeImportManager relationshipTypeImportManager;
107 public TypesUploadServlet(UserBusinessLogic userBusinessLogic,
108 ComponentInstanceBusinessLogic componentInstanceBL,
109 ComponentsUtils componentsUtils, ServletUtils servletUtils,
110 ResourceImportManager resourceImportManager,
111 CapabilityTypeImportManager capabilityTypeImportManager,
112 InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager,
113 CategoriesImportManager categoriesImportManager,
114 DataTypeImportManager dataTypeImportManager,
115 GroupTypeImportManager groupTypeImportManager,
116 PolicyTypeImportManager policyTypeImportManager,
117 RelationshipTypeImportManager relationshipTypeImportManager) {
118 super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
119 this.capabilityTypeImportManager = capabilityTypeImportManager;
120 this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager;
121 this.categoriesImportManager = categoriesImportManager;
122 this.dataTypeImportManager = dataTypeImportManager;
123 this.groupTypeImportManager = groupTypeImportManager;
124 this.policyTypeImportManager = policyTypeImportManager;
125 this.relationshipTypeImportManager = relationshipTypeImportManager;
130 @Operation(description = "Create Capability Type from yaml", method = "POST",
131 summary = "Returns created Capability Type", responses = {
132 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
133 @ApiResponse(responseCode = "201", description = "Capability Type created"),
134 @ApiResponse(responseCode = "403", description = "Restricted operation"),
135 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
136 @ApiResponse(responseCode = "409", description = "Capability Type already exist")})
137 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
138 public Response uploadCapabilityType(@Parameter(description = "FileInputStream") @FormDataParam("capabilityTypeZip") File file,
139 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
140 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod =
141 (responseWrapper, ymlPayload) -> createElementsType(responseWrapper,
142 () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload));
143 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator,
144 NodeTypeEnum.CapabilityType.name());
148 @Path("/relationship")
149 @Operation(description = "Create Relationship Type from yaml", method = "POST",
150 summary = "Returns created Relationship Type", responses = {
151 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
152 @ApiResponse(responseCode = "201", description = "Relationship Type created"),
153 @ApiResponse(responseCode = "403", description = "Restricted operation"),
154 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
155 @ApiResponse(responseCode = "409", description = "Relationship Type already exist")})
156 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
157 public Response uploadRelationshipType(@Parameter(description = "FileInputStream") @FormDataParam("relationshipTypeZip") File file,
158 @Context final HttpServletRequest request,
159 @HeaderParam("USER_ID") String creator) {
160 return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator,
161 NodeTypeEnum.RelationshipType.getName());
165 @Path("/interfaceLifecycle")
166 @Operation(description = "Create Interface Lyfecycle Type from yaml", method = "POST",
167 summary = "Returns created Interface Lifecycle Type", responses = {
168 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
169 @ApiResponse(responseCode = "201", description = "Interface Lifecycle Type created"),
170 @ApiResponse(responseCode = "403", description = "Restricted operation"),
171 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
172 @ApiResponse(responseCode = "409", description = "Interface Lifecycle Type already exist")})
173 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
174 public Response uploadInterfaceLifecycleType(
175 @Parameter(description = "FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file,
176 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
177 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod =
178 (responseWrapper, ymlPayload) -> createElementsType(responseWrapper,
179 () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload));
180 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types");
185 @Operation(description = "Create Categories from yaml", method = "POST", summary = "Returns created categories",
186 responses = {@ApiResponse(
187 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
188 @ApiResponse(responseCode = "201", description = "Categories created"),
189 @ApiResponse(responseCode = "403", description = "Restricted operation"),
190 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
191 @ApiResponse(responseCode = "409", description = "Category already exist")})
192 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
193 public Response uploadCategories(@Parameter(description = "FileInputStream") @FormDataParam("categoriesZip") File file,
194 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
195 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod =
196 (responseWrapper, ymlPayload) -> createElementsType(responseWrapper,
197 () -> categoriesImportManager.createCategories(ymlPayload));
198 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories");
203 @Operation(description = "Create Categories from yaml", method = "POST", summary = "Returns created data types",
204 responses = {@ApiResponse(
205 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
206 @ApiResponse(responseCode = "201", description = "Data types created"),
207 @ApiResponse(responseCode = "403", description = "Restricted operation"),
208 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
209 @ApiResponse(responseCode = "409", description = "Data types already exist")})
210 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
211 public Response uploadDataTypes(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesZip") File file,
212 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
213 ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = this::createDataTypes;
214 return uploadElementTypeServletLogic(createElementsMethod, file, request, creator,
215 NodeTypeEnum.DataType.getName());
220 @Operation(description = "Create GroupTypes from yaml", method = "POST", summary = "Returns created group types",
221 responses = {@ApiResponse(
222 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
223 @ApiResponse(responseCode = "201", description = "group types created"),
224 @ApiResponse(responseCode = "403", description = "Restricted operation"),
225 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
226 @ApiResponse(responseCode = "409", description = "group types already exist")})
227 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
228 public Response uploadGroupTypes(
229 @Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
230 @Parameter(description = "FileInputStream") @FormDataParam("groupTypesZip") File file,
231 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
232 Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
233 return uploadTypesWithMetaData(this::createGroupTypes, typesMetadata, file, request, creator,
234 NodeTypeEnum.GroupType.getName());
238 @Path("/policytypes")
239 @Operation(description = "Create PolicyTypes from yaml", method = "POST", summary = "Returns created policy types",
240 responses = {@ApiResponse(
241 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
242 @ApiResponse(responseCode = "201", description = "policy types created"),
243 @ApiResponse(responseCode = "403", description = "Restricted operation"),
244 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
245 @ApiResponse(responseCode = "409", description = "policy types already exist")})
246 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
247 public Response uploadPolicyTypes(
248 @Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
249 @Parameter(description = "FileInputStream") @FormDataParam("policyTypesZip") File file,
250 @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
251 Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
252 return uploadTypesWithMetaData(this::createPolicyTypes, typesMetadata, file, request, creator,
253 NodeTypeEnum.PolicyType.getName());
256 private Map<String, ToscaTypeMetadata> getTypesMetadata(String toscaTypesMetaData) {
257 return gson.fromJson(toscaTypesMetaData, new TypeToken<Map<String, ToscaTypeMetadata>>(){}.getType());
260 private Response uploadElementTypeServletLogic(ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod, File file, final HttpServletRequest request, String creator, String elementTypeName) {
262 String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
264 Wrapper<String> yamlStringWrapper = new Wrapper<>();
266 String url = request.getMethod() + " " + request.getRequestURI();
267 log.debug("Start handle request of {}", url);
268 Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
269 if (responseWrapper.isEmpty()) {
270 fillZipContents(yamlStringWrapper, file);
272 if (responseWrapper.isEmpty()) {
273 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement());
275 return responseWrapper.getInnerElement();
276 } catch (Exception e) {
277 log.debug("create {} failed with exception:", elementTypeName, e);
278 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
279 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
283 private Wrapper<Response> doUploadTypeValidations(final HttpServletRequest request, String userId, File file) {
284 Wrapper<Response> responseWrapper = new Wrapper<>();
285 Wrapper<User> userWrapper = new Wrapper<>();
287 String url = request.getMethod() + " " + request.getRequestURI();
288 log.debug("Start handle request of {}", url);
290 validateUserExist(responseWrapper, userWrapper, userId);
292 if (responseWrapper.isEmpty()) {
293 validateUserRole(responseWrapper, userWrapper.getInnerElement());
296 if (responseWrapper.isEmpty()) {
297 validateDataNotNull(responseWrapper, file);
299 return responseWrapper;
302 private Response uploadTypesWithMetaData(ConsumerTwoParam<Wrapper<Response>, ToscaTypeImportData> createElementsMethod, Map<String, ToscaTypeMetadata> typesMetaData, File file, final HttpServletRequest request, String creator, String elementTypeName) {
304 String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
305 Wrapper<String> yamlStringWrapper = new Wrapper<>();
307 Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
308 if (responseWrapper.isEmpty()) {
309 fillZipContents(yamlStringWrapper, file);
311 if (responseWrapper.isEmpty()) {
312 ToscaTypeImportData toscaTypeImportData = new ToscaTypeImportData(yamlStringWrapper.getInnerElement(), typesMetaData);
313 createElementsMethod.accept(responseWrapper, toscaTypeImportData);
315 return responseWrapper.getInnerElement();
316 } catch (Exception e) {
317 log.debug("create {} failed with exception:", elementTypeName, e);
318 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
319 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
323 private <T> void createElementsType(Wrapper<Response> responseWrapper, Supplier<Either<T, ResponseFormat>> elementsCreater) {
324 Either<T, ResponseFormat> eitherResult = elementsCreater.get();
325 if (eitherResult.isRight()) {
326 Response response = buildErrorResponse(eitherResult.right().value());
327 responseWrapper.setInnerElement(response);
330 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), RepresentationUtils.toRepresentation(eitherResult.left().value()));
331 responseWrapper.setInnerElement(response);
332 } catch (Exception e) {
333 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
334 responseWrapper.setInnerElement(response);
335 log.error("#createElementsType - json serialization failed with error: ", e);
341 private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml) {
342 final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml =
343 () -> dataTypeImportManager.createDataTypes(dataTypesYml);
344 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml,
345 ActionStatus.DATA_TYPE_ALREADY_EXIST, NodeTypeEnum.DataType.name());
349 private void createGroupTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData) {
350 final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml =
351 () -> groupTypeImportManager.createGroupTypes(toscaTypeImportData);
352 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml,
353 ActionStatus.GROUP_TYPE_ALREADY_EXIST, NodeTypeEnum.GroupType.name());
357 private void createPolicyTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData) {
358 final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml =
359 () -> policyTypeImportManager.createPolicyTypes(toscaTypeImportData);
360 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml,
361 ActionStatus.POLICY_TYPE_ALREADY_EXIST, NodeTypeEnum.PolicyType.name());
365 private <ElementTypeDefinition> void buildStatusForElementTypeCreate(Wrapper<Response> responseWrapper, Supplier<Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml, ActionStatus alreadyExistStatus, String elementTypeName) {
366 Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> eitherResult = generateElementTypeFromYml.get();
368 if (eitherResult.isRight()) {
369 Response response = buildErrorResponse(eitherResult.right().value());
370 responseWrapper.setInnerElement(response);
372 Object representation;
374 List<ImmutablePair<ElementTypeDefinition, Boolean>> list = eitherResult.left().value();
375 ActionStatus status = ActionStatus.OK;
378 // Group result by the right value - true or false.
379 // I.e., get the number of data types which are new and
381 Map<Boolean, List<ImmutablePair<ElementTypeDefinition, Boolean>>> collect = list.stream().collect(Collectors.groupingBy(ImmutablePair<ElementTypeDefinition, Boolean>::getRight));
382 if (collect != null) {
383 Set<Boolean> keySet = collect.keySet();
384 if (keySet.size() == 1) {
385 Boolean isNew = keySet.iterator().next();
387 // all data types created at the first time
388 status = ActionStatus.CREATED;
390 // All data types already exists
392 status = alreadyExistStatus;
397 representation = RepresentationUtils.toRepresentation(eitherResult.left().value());
399 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(status), representation);
400 responseWrapper.setInnerElement(response);
402 } catch (IOException e) {
403 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
404 log.debug("failed to convert {} to json", elementTypeName, e);
405 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
406 responseWrapper.setInnerElement(response);
410 // relationship types
411 private void createRelationshipTypes(Wrapper<Response> responseWrapper, String relationshipTypesYml) {
412 final Supplier<Either<List<ImmutablePair<RelationshipTypeDefinition, Boolean>>, ResponseFormat>>
413 generateElementTypeFromYml =
414 () -> relationshipTypeImportManager.createRelationshipTypes(relationshipTypesYml);
415 buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml,
416 ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST, NodeTypeEnum.RelationshipType.name());