309bff28c33905f08084bacef7f26a146cf0c110
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / servlets / TypesUploadServlet.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 package org.openecomp.sdc.be.servlets;
21
22 import com.fasterxml.jackson.databind.ObjectMapper;
23 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
24 import com.google.gson.reflect.TypeToken;
25 import com.jcabi.aspects.Loggable;
26 import com.networknt.schema.JsonSchemaFactory;
27 import com.networknt.schema.SpecVersion;
28 import com.networknt.schema.ValidationMessage;
29 import fj.data.Either;
30 import io.swagger.v3.oas.annotations.Operation;
31 import io.swagger.v3.oas.annotations.Parameter;
32 import io.swagger.v3.oas.annotations.media.ArraySchema;
33 import io.swagger.v3.oas.annotations.media.Content;
34 import io.swagger.v3.oas.annotations.media.Schema;
35 import io.swagger.v3.oas.annotations.responses.ApiResponse;
36 import io.swagger.v3.oas.annotations.servers.Server;
37 import io.swagger.v3.oas.annotations.tags.Tag;
38 import org.apache.commons.lang3.tuple.ImmutablePair;
39 import org.glassfish.jersey.media.multipart.FormDataParam;
40 import org.jetbrains.annotations.NotNull;
41 import org.openecomp.sdc.be.components.impl.ArtifactTypeImportManager;
42 import org.openecomp.sdc.be.components.impl.CapabilityTypeImportManager;
43 import org.openecomp.sdc.be.components.impl.CategoriesImportManager;
44 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
45 import org.openecomp.sdc.be.components.impl.DataTypeImportManager;
46 import org.openecomp.sdc.be.components.impl.GroupTypeImportManager;
47 import org.openecomp.sdc.be.components.impl.InterfaceLifecycleTypeImportManager;
48 import org.openecomp.sdc.be.components.impl.PolicyTypeImportManager;
49 import org.openecomp.sdc.be.components.impl.RelationshipTypeImportManager;
50 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
51 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
52 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
53 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
54 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
55 import org.openecomp.sdc.be.config.BeEcompErrorManager;
56 import org.openecomp.sdc.be.dao.api.ActionStatus;
57 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
58 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
59 import org.openecomp.sdc.be.impl.ComponentsUtils;
60 import org.openecomp.sdc.be.impl.ServletUtils;
61 import org.openecomp.sdc.be.model.DataTypeDefinition;
62 import org.openecomp.sdc.be.model.GroupTypeDefinition;
63 import org.openecomp.sdc.be.model.PolicyTypeDefinition;
64 import org.openecomp.sdc.be.model.RelationshipTypeDefinition;
65 import org.openecomp.sdc.be.model.User;
66 import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata;
67 import org.openecomp.sdc.common.api.Constants;
68 import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerFourParam;
69 import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerTwoParam;
70 import org.openecomp.sdc.common.datastructure.Wrapper;
71 import org.openecomp.sdc.common.log.wrappers.Logger;
72 import org.openecomp.sdc.exception.ResponseFormat;
73 import org.springframework.stereotype.Controller;
74
75 import javax.inject.Inject;
76 import javax.servlet.http.HttpServletRequest;
77 import javax.ws.rs.Consumes;
78 import javax.ws.rs.HeaderParam;
79 import javax.ws.rs.POST;
80 import javax.ws.rs.Path;
81 import javax.ws.rs.Produces;
82 import javax.ws.rs.core.Context;
83 import javax.ws.rs.core.MediaType;
84 import javax.ws.rs.core.Response;
85 import java.io.File;
86 import java.io.FileInputStream;
87 import java.io.IOException;
88 import java.io.InputStream;
89 import java.nio.charset.StandardCharsets;
90 import java.util.HashSet;
91 import java.util.List;
92 import java.util.Map;
93 import java.util.Set;
94 import java.util.function.Supplier;
95 import java.util.stream.Collectors;
96
97 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
98 @Path("/v1/catalog/uploadType")
99 @Consumes(MediaType.MULTIPART_FORM_DATA)
100 @Produces(MediaType.APPLICATION_JSON)
101 @Tag(name = "SDCE-2 APIs")
102 @Server(url = "/sdc2/rest")
103 @Controller
104 public class TypesUploadServlet extends AbstractValidationsServlet {
105
106     private static final String CREATE = "Create ";
107     private static final String START_HANDLE_REQUEST_OF = "Start handle request of {}";
108     private static final String CREATE_FAILED_WITH_EXCEPTION = "create {} failed with exception:";
109     private static final Logger log = Logger.getLogger(TypesUploadServlet.class);
110     private final CapabilityTypeImportManager capabilityTypeImportManager;
111     private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager;
112     private final CategoriesImportManager categoriesImportManager;
113     private final DataTypeImportManager dataTypeImportManager;
114     private final GroupTypeImportManager groupTypeImportManager;
115     private final PolicyTypeImportManager policyTypeImportManager;
116     private final RelationshipTypeImportManager relationshipTypeImportManager;
117     private final ArtifactTypeImportManager artifactTypeImportManager;
118
119     @Inject
120     public TypesUploadServlet(ComponentInstanceBusinessLogic componentInstanceBL,
121                               ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager,
122                               CapabilityTypeImportManager capabilityTypeImportManager,
123                               InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager,
124                               CategoriesImportManager categoriesImportManager, DataTypeImportManager dataTypeImportManager,
125                               GroupTypeImportManager groupTypeImportManager, PolicyTypeImportManager policyTypeImportManager,
126                               RelationshipTypeImportManager relationshipTypeImportManager, ArtifactTypeImportManager artifactTypeImportManager) {
127         super(componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
128         this.capabilityTypeImportManager = capabilityTypeImportManager;
129         this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager;
130         this.categoriesImportManager = categoriesImportManager;
131         this.dataTypeImportManager = dataTypeImportManager;
132         this.groupTypeImportManager = groupTypeImportManager;
133         this.policyTypeImportManager = policyTypeImportManager;
134         this.relationshipTypeImportManager = relationshipTypeImportManager;
135         this.artifactTypeImportManager = artifactTypeImportManager;
136     }
137
138     @POST
139     @Path("/capability")
140     @Operation(description = "Create Capability Type from yaml", method = "POST", summary = "Returns created Capability Type", responses = {
141             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
142             @ApiResponse(responseCode = "201", description = "Capability Type created"),
143             @ApiResponse(responseCode = "403", description = "Restricted operation"),
144             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
145             @ApiResponse(responseCode = "409", description = "Capability Type already exist")})
146     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
147     public Response uploadCapabilityType(@Parameter(description = "FileInputStream") @FormDataParam("capabilityTypeZip") File file,
148                                          @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
149                                          @Parameter(description = "model name") @FormDataParam("model") String modelName,
150                                          @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
151         ConsumerFourParam<Wrapper<Response>, String, String, Boolean> createElementsMethod = (responseWrapper, ymlPayload, model, includeToModelImport) ->
152                 createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload, modelName,
153                         includeToModelDefaultImports));
154         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name(), modelName,
155                 includeToModelDefaultImports);
156     }
157
158     @POST
159     @Path("/relationship")
160     @Operation(description = "Create Relationship Type from yaml", method = "POST", summary = "Returns created Relationship Type", responses = {
161             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
162             @ApiResponse(responseCode = "201", description = "Relationship Type created"),
163             @ApiResponse(responseCode = "403", description = "Restricted operation"),
164             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
165             @ApiResponse(responseCode = "409", description = "Relationship Type already exist")})
166     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
167     public Response uploadRelationshipType(@Parameter(description = "FileInputStream") @FormDataParam("relationshipTypeZip") File file,
168                                            @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
169                                            @Parameter(description = "model name") @FormDataParam("model") String modelName,
170                                            @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
171         return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator, NodeTypeEnum.RelationshipType.getName(),
172                 modelName, includeToModelDefaultImports);
173     }
174
175     @POST
176     @Path("/interfaceLifecycle")
177     @Operation(description = "Create Interface Lyfecycle Type from yaml", method = "POST", summary = "Returns created Interface Lifecycle Type", responses = {
178             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
179             @ApiResponse(responseCode = "201", description = "Interface Lifecycle Type created"),
180             @ApiResponse(responseCode = "403", description = "Restricted operation"),
181             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
182             @ApiResponse(responseCode = "409", description = "Interface Lifecycle Type already exist")})
183     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
184     public Response uploadInterfaceLifecycleType(@Parameter(description = "FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file,
185                                                  @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
186                                                  @Parameter(description = "model name") @FormDataParam("model") String modelName,
187                                                  @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
188         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
189                 createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload, modelName,
190                         includeToModelDefaultImports));
191         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types");
192     }
193
194     @POST
195     @Path("/artifactTypes")
196     @Operation(description = "Create Tosca Artifact types from yaml", method = "POST", summary = "Returns created Tosca artifact types", responses = {
197             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
198             @ApiResponse(responseCode = "201", description = "Tosca Artifact types created"),
199             @ApiResponse(responseCode = "403", description = "Restricted operation"),
200             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
201             @ApiResponse(responseCode = "409", description = "Tosca Artifact Type already exist")})
202     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
203     public Response uploadArtifactTypes(@Parameter(description = "Zip file containing a yaml with the TOSCA artifact types definition")
204                                         @FormDataParam("artifactsZip") File file,
205                                         @Parameter(description = "model name") @FormDataParam("model") String modelName,
206                                         @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
207                                         @Parameter(description = "A flag to add types to the default imports")
208                                         @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
209         final ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
210                 createElementsType(responseWrapper,
211                         () -> artifactTypeImportManager.createArtifactTypes(ymlPayload, modelName, includeToModelDefaultImports));
212         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.ArtifactType.getName());
213     }
214
215     @POST
216     @Path("/categories")
217     @Operation(description = "Create Categories from yaml", method = "POST", summary = "Returns created categories", responses = {
218             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
219             @ApiResponse(responseCode = "201", description = "Categories created"),
220             @ApiResponse(responseCode = "403", description = "Restricted operation"),
221             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
222             @ApiResponse(responseCode = "409", description = "Category already exist")})
223     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
224     public Response uploadCategories(@Parameter(description = "FileInputStream") @FormDataParam("categoriesZip") File file,
225                                      @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
226         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
227                 createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload));
228         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories");
229     }
230
231     @POST
232     @Path("/datatypes")
233     @Operation(description = "Create Data Types from zip", method = "POST", summary = "Returns created data types", responses = {
234             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
235             @ApiResponse(responseCode = "201", description = "Data types created"),
236             @ApiResponse(responseCode = "403", description = "Restricted operation"),
237             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
238             @ApiResponse(responseCode = "409", description = "Data types already exist")})
239     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
240     public Response uploadDataTypes(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesZip") File file,
241                                     @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
242                                     @Parameter(description = "model name") @FormDataParam("model") String modelName,
243                                     @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
244         return uploadElementTypeServletLogic(this::createDataTypes, file, request, creator, NodeTypeEnum.DataType.getName(), modelName,
245                 includeToModelDefaultImports);
246     }
247
248     @POST
249     @Path("/datatypesyaml")
250     @Operation(description = "Create Data Types from yaml", method = "POST", summary = "Returns created data types", responses = {
251             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
252             @ApiResponse(responseCode = "201", description = "Data types created"),
253             @ApiResponse(responseCode = "403", description = "Restricted operation"),
254             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
255             @ApiResponse(responseCode = "409", description = "Data types already exist")})
256     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
257     public Response uploadDataTypesYaml(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesYaml") File file,
258                                         @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
259                                         @Parameter(description = "model name") @FormDataParam("model") String modelName,
260                                         @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
261         return uploadElementTypeServletLogicYaml(this::createDataTypes, file, request, creator, NodeTypeEnum.DataType.getName(), modelName,
262                 includeToModelDefaultImports);
263     }
264
265     @POST
266     @Path("/grouptypes")
267     @Operation(description = "Create GroupTypes from yaml", method = "POST", summary = "Returns created group types", responses = {
268             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
269             @ApiResponse(responseCode = "201", description = "group types created"),
270             @ApiResponse(responseCode = "403", description = "Restricted operation"),
271             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
272             @ApiResponse(responseCode = "409", description = "group types already exist")})
273     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
274     public Response uploadGroupTypes(@Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
275                                      @Parameter(description = "model name") @FormDataParam("model") String modelName,
276                                      @Parameter(description = "FileInputStream") @FormDataParam("groupTypesZip") File file,
277                                      @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
278                                      @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
279         Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
280         return uploadTypesWithMetaData(this::createGroupTypes, typesMetadata, file, request, creator, NodeTypeEnum.GroupType.getName(), modelName,
281                 includeToModelDefaultImports);
282     }
283
284     @POST
285     @Path("/policytypes")
286     @Operation(description = "Create PolicyTypes from yaml", method = "POST", summary = "Returns created policy types", responses = {
287             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
288             @ApiResponse(responseCode = "201", description = "policy types created"),
289             @ApiResponse(responseCode = "403", description = "Restricted operation"),
290             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
291             @ApiResponse(responseCode = "409", description = "policy types already exist")})
292     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
293     public Response uploadPolicyTypes(@Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
294                                       @Parameter(description = "model name") @FormDataParam("model") String modelName,
295                                       @Parameter(description = "FileInputStream") @FormDataParam("policyTypesZip") File file,
296                                       @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
297                                       @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
298         Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
299         return uploadTypesWithMetaData(this::createPolicyTypes, typesMetadata, file, request, creator, NodeTypeEnum.PolicyType.getName(), modelName,
300                 includeToModelDefaultImports);
301     }
302
303     private Map<String, ToscaTypeMetadata> getTypesMetadata(String toscaTypesMetaData) {
304         return gson.fromJson(toscaTypesMetaData, new TypeToken<Map<String, ToscaTypeMetadata>>() {
305         }.getType());
306     }
307
308     private Response uploadElementTypeServletLogic(ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod, File file,
309                                                    final HttpServletRequest request, String creator, String elementTypeName) {
310         init();
311         String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
312         try {
313             Wrapper<String> yamlStringWrapper = new Wrapper<>();
314             String url = request.getMethod() + " " + request.getRequestURI();
315             log.debug(START_HANDLE_REQUEST_OF, url);
316             Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
317             if (responseWrapper.isEmpty()) {
318                 fillZipContents(yamlStringWrapper, file);
319             }
320             if (responseWrapper.isEmpty()) {
321                 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement());
322             }
323             return responseWrapper.getInnerElement();
324         } catch (Exception e) {
325             log.debug(CREATE_FAILED_WITH_EXCEPTION, elementTypeName, e);
326             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
327             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
328         }
329     }
330
331     private Response uploadElementTypeServletLogic(final ConsumerFourParam<Wrapper<Response>, String, String, Boolean> createElementsMethod,
332                                                    final File file, final HttpServletRequest request, final String creator,
333                                                    final String elementTypeName, final String modelName, final boolean includeToModelDefaultImports) {
334         init();
335         final String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
336         try {
337             final Wrapper<String> yamlStringWrapper = new Wrapper<>();
338             final String url = request.getMethod() + " " + request.getRequestURI();
339             log.debug(START_HANDLE_REQUEST_OF, url);
340             final Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
341             if (responseWrapper.isEmpty()) {
342                 fillZipContents(yamlStringWrapper, file);
343                 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement(), modelName, includeToModelDefaultImports);
344             }
345             return responseWrapper.getInnerElement();
346         } catch (final Exception e) {
347             log.debug(CREATE_FAILED_WITH_EXCEPTION, elementTypeName, e);
348             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
349             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
350         }
351     }
352
353     private Response uploadElementTypeServletLogicYaml(final ConsumerFourParam<Wrapper<Response>, String, String, Boolean> createElementsMethod,
354                                                        final File file, final HttpServletRequest request, final String creator,
355                                                        final String elementTypeName, final String modelName,
356                                                        final boolean includeToModelDefaultImports) {
357         init();
358         final Set<ValidationMessage> validationMessages = validateYaml(file);
359         if (!validationMessages.isEmpty()) {
360             throw new ByActionStatusComponentException(ActionStatus.YAML_IS_INVALID, validationMessages.stream().map(validationMessage -> {
361                 return validationMessage.getMessage();
362             }).collect(Collectors.joining("\n")));
363         }
364         final String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
365         try {
366             final String url = request.getMethod() + " " + request.getRequestURI();
367             log.debug(START_HANDLE_REQUEST_OF, url);
368             final Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
369             final String yamlAsString = getFileAsString(file);
370             if (responseWrapper.isEmpty()) {
371                 log.debug("received yaml: {}", yamlAsString);
372                 createElementsMethod.accept(responseWrapper, yamlAsString, modelName, includeToModelDefaultImports);
373             }
374
375             return responseWrapper.getInnerElement();
376         } catch (final Exception e) {
377             log.debug(CREATE_FAILED_WITH_EXCEPTION, elementTypeName, e);
378             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
379             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
380         }
381     }
382
383     private Set<ValidationMessage> validateYaml(final File file) {
384         final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
385         final JsonSchemaFactory factory =
386                 JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)).objectMapper(mapper).build();
387
388         final Set<ValidationMessage> validationMessages = new HashSet<>();
389         try (final InputStream yamlFile = new FileInputStream(file);
390              final InputStream schemaFile = Thread.currentThread().getContextClassLoader().getResourceAsStream("validateYaml/schema.json")) {
391             validationMessages.addAll(factory.getSchema(schemaFile).validate(mapper.readTree(yamlFile)));
392         } catch (final IOException e) {
393             ValidationMessage.Builder builder = new ValidationMessage.Builder();
394             builder.customMessage(e.getMessage());
395             validationMessages.add(builder.build());
396         }
397
398         return validationMessages;
399     }
400
401     @NotNull
402     private String getFileAsString(File file) throws IOException {
403         try (final FileInputStream fl = new FileInputStream(file)) {
404             byte[] arr = new byte[(int) file.length()];
405             int read = fl.read(arr);
406             if (read > 0) {
407                 return new String(arr, StandardCharsets.UTF_8);
408             } else {
409                 throw new IOException(String.format("Failed to read bytes from '%s'", file.getName()));
410             }
411         }
412     }
413
414     private Wrapper<Response> doUploadTypeValidations(final HttpServletRequest request, String userId, File file) {
415         Wrapper<Response> responseWrapper = new Wrapper<>();
416         Wrapper<User> userWrapper = new Wrapper<>();
417         String url = request.getMethod() + " " + request.getRequestURI();
418         log.debug(START_HANDLE_REQUEST_OF, url);
419         validateUserExist(responseWrapper, userWrapper, userId);
420         if (responseWrapper.isEmpty()) {
421             validateUserRole(responseWrapper, userWrapper.getInnerElement());
422         }
423         if (responseWrapper.isEmpty()) {
424             validateDataNotNull(responseWrapper, file);
425         }
426         return responseWrapper;
427     }
428
429     private Response uploadTypesWithMetaData(ConsumerFourParam<Wrapper<Response>, ToscaTypeImportData, String, Boolean> createElementsMethod,
430                                              Map<String, ToscaTypeMetadata> typesMetaData, File file, final HttpServletRequest request,
431                                              String creator, String elementTypeName, String modelName, final boolean includeToModelDefaultImports) {
432         init();
433         String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
434         Wrapper<String> yamlStringWrapper = new Wrapper<>();
435         try {
436             Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
437             if (responseWrapper.isEmpty()) {
438                 fillZipContents(yamlStringWrapper, file);
439             }
440             if (responseWrapper.isEmpty()) {
441                 ToscaTypeImportData toscaTypeImportData = new ToscaTypeImportData(yamlStringWrapper.getInnerElement(), typesMetaData);
442                 createElementsMethod.accept(responseWrapper, toscaTypeImportData, modelName, includeToModelDefaultImports);
443             }
444             return responseWrapper.getInnerElement();
445         } catch (Exception e) {
446             log.debug(CREATE_FAILED_WITH_EXCEPTION, elementTypeName, e);
447             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
448             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
449         }
450     }
451
452     private <T> void createElementsType(Wrapper<Response> responseWrapper, Supplier<Either<T, ResponseFormat>> elementsCreater) {
453         Either<T, ResponseFormat> eitherResult = elementsCreater.get();
454         if (eitherResult.isRight()) {
455             responseWrapper.setInnerElement(buildErrorResponse(eitherResult.right().value()));
456         } else {
457             try {
458                 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED),
459                         RepresentationUtils.toRepresentation(eitherResult.left().value()));
460                 responseWrapper.setInnerElement(response);
461             } catch (Exception e) {
462                 responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)));
463                 log.error("#createElementsType - json serialization failed with error: ", e);
464             }
465         }
466     }
467
468     // data types
469     private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml, final String modelName,
470                                  final boolean includeToModelDefaultImports) {
471         final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () ->
472                 dataTypeImportManager.createDataTypes(dataTypesYml, modelName, includeToModelDefaultImports);
473         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.DATA_TYPE_ALREADY_EXIST,
474                 NodeTypeEnum.DataType.name());
475     }
476
477     // group types
478     private void createGroupTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData, String modelName,
479                                   final boolean includeToModelDefaultImports) {
480         final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () ->
481                 groupTypeImportManager.createGroupTypes(toscaTypeImportData, modelName, includeToModelDefaultImports);
482         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.GROUP_TYPE_ALREADY_EXIST,
483                 NodeTypeEnum.GroupType.name());
484     }
485
486     // policy types
487     private void createPolicyTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData, String modelName,
488                                    final boolean includeToModelDefaultImports) {
489         final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () ->
490                 policyTypeImportManager.createPolicyTypes(toscaTypeImportData, modelName, includeToModelDefaultImports);
491         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.POLICY_TYPE_ALREADY_EXIST,
492                 NodeTypeEnum.PolicyType.name());
493     }
494
495     // data types
496     private <T extends ToscaDataDefinition> void buildStatusForElementTypeCreate(Wrapper<Response> responseWrapper,
497                                                                                  Supplier<Either<List<ImmutablePair<T, Boolean>>, ResponseFormat>> generateElementTypeFromYml,
498                                                                                  ActionStatus alreadyExistStatus, String elementTypeName) {
499         Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> eitherResult = generateElementTypeFromYml.get();
500         if (eitherResult.isRight()) {
501             responseWrapper.setInnerElement(buildErrorResponse(eitherResult.right().value()));
502         } else {
503
504             try {
505                 final List<ImmutablePair<T, Boolean>> list = eitherResult.left().value();
506                 ActionStatus status = ActionStatus.OK;
507                 if (list != null) {
508                     // Group result by the right value - true or false.
509                     // I.e., get the number of data types which are new and which are old.
510                     final Map<Boolean, List<ImmutablePair<T, Boolean>>> collect =
511                             list.stream().collect(Collectors.groupingBy(ImmutablePair<T, Boolean>::getRight));
512                     if (collect != null) {
513                         Set<Boolean> keySet = collect.keySet();
514                         if (keySet.size() == 1) {
515                             Boolean isNew = keySet.iterator().next();
516                             if (Boolean.TRUE.equals(isNew)) {
517                                 // all data types created at the first time
518                                 status = ActionStatus.CREATED;
519                             } else {
520                                 // All data types already exists
521                                 status = alreadyExistStatus;
522                             }
523                         }
524                     }
525                 }
526                 final Object representation = RepresentationUtils.toRepresentation(eitherResult.left().value());
527                 responseWrapper.setInnerElement(buildOkResponse(getComponentsUtils().getResponseFormat(status), representation));
528             } catch (IOException e) {
529                 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE + elementTypeName);
530                 log.debug("failed to convert {} to json", elementTypeName, e);
531                 responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)));
532             }
533         }
534     }
535
536     // relationship types
537     private void createRelationshipTypes(final Wrapper<Response> responseWrapper,
538                                          final String relationshipTypesYml,
539                                          final String modelName,
540                                          final boolean includeToModelDefaultImports) {
541         final Supplier<Either<List<ImmutablePair<RelationshipTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> relationshipTypeImportManager
542                 .createRelationshipTypes(relationshipTypesYml, modelName, includeToModelDefaultImports);
543         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST,
544                 NodeTypeEnum.RelationshipType.name());
545     }
546 }