Sync Integ to Master
[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
21 package org.openecomp.sdc.be.servlets;
22
23 import com.jcabi.aspects.Loggable;
24 import fj.data.Either;
25 import io.swagger.annotations.Api;
26 import io.swagger.annotations.ApiOperation;
27 import io.swagger.annotations.ApiParam;
28 import io.swagger.annotations.ApiResponse;
29 import io.swagger.annotations.ApiResponses;
30 import org.apache.commons.lang3.tuple.ImmutablePair;
31 import org.glassfish.jersey.media.multipart.FormDataParam;
32 import org.openecomp.sdc.be.components.impl.CapabilityTypeImportManager;
33 import org.openecomp.sdc.be.components.impl.CategoriesImportManager;
34 import org.openecomp.sdc.be.components.impl.DataTypeImportManager;
35 import org.openecomp.sdc.be.components.impl.GroupTypeImportManager;
36 import org.openecomp.sdc.be.components.impl.InterfaceLifecycleTypeImportManager;
37 import org.openecomp.sdc.be.components.impl.PolicyTypeImportManager;
38 import org.openecomp.sdc.be.config.BeEcompErrorManager;
39 import org.openecomp.sdc.be.dao.api.ActionStatus;
40 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
41 import org.openecomp.sdc.be.model.DataTypeDefinition;
42 import org.openecomp.sdc.be.model.GroupTypeDefinition;
43 import org.openecomp.sdc.be.model.PolicyTypeDefinition;
44 import org.openecomp.sdc.be.model.User;
45 import org.openecomp.sdc.common.api.Constants;
46 import org.openecomp.sdc.common.datastructure.FunctionalInterfaces.ConsumerTwoParam;
47 import org.openecomp.sdc.common.datastructure.Wrapper;
48 import org.openecomp.sdc.exception.ResponseFormat;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.stereotype.Controller;
52 import javax.servlet.http.HttpServletRequest;
53 import javax.ws.rs.Consumes;
54 import javax.ws.rs.HeaderParam;
55 import javax.ws.rs.POST;
56 import javax.ws.rs.Path;
57 import javax.ws.rs.Produces;
58 import javax.ws.rs.core.Context;
59 import javax.ws.rs.core.MediaType;
60 import javax.ws.rs.core.Response;
61 import java.io.File;
62 import java.io.IOException;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Set;
66 import java.util.function.Supplier;
67 import java.util.stream.Collectors;
68
69 import javax.servlet.http.HttpServletRequest;
70 import javax.ws.rs.Consumes;
71 import javax.ws.rs.HeaderParam;
72 import javax.ws.rs.POST;
73 import javax.ws.rs.Path;
74 import javax.ws.rs.Produces;
75 import javax.ws.rs.core.Context;
76 import javax.ws.rs.core.MediaType;
77 import javax.ws.rs.core.Response;
78 import java.io.File;
79 import java.io.IOException;
80 import java.util.List;
81 import java.util.Map;
82 import java.util.Set;
83 import java.util.function.Supplier;
84 import java.util.stream.Collectors;
85 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
86 @Path("/v1/catalog/uploadType")
87 @Api(value = "Catalog Types Upload")
88 @Controller
89 public class TypesUploadServlet extends AbstractValidationsServlet {
90     private static final Logger log = LoggerFactory.getLogger(TypesUploadServlet.class);
91     private CapabilityTypeImportManager capabilityTypeImportManager;
92
93     private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager;
94
95     private final CategoriesImportManager categoriesImportManager;
96
97     private final DataTypeImportManager dataTypeImportManager;
98
99     private final GroupTypeImportManager groupTypeImportManager;
100
101     private final PolicyTypeImportManager policyTypeImportManager;
102
103     public TypesUploadServlet(CapabilityTypeImportManager capabilityTypeImportManager, InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager, CategoriesImportManager categoriesImportManager, DataTypeImportManager dataTypeImportManager, GroupTypeImportManager groupTypeImportManager, PolicyTypeImportManager policyTypeImportManager) {
104         this.capabilityTypeImportManager = capabilityTypeImportManager;
105         this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager;
106         this.categoriesImportManager = categoriesImportManager;
107         this.dataTypeImportManager = dataTypeImportManager;
108         this.groupTypeImportManager = groupTypeImportManager;
109         this.policyTypeImportManager = policyTypeImportManager;
110     }
111
112     @POST
113     @Path("/capability")
114     @Consumes(MediaType.MULTIPART_FORM_DATA)
115     @Produces(MediaType.APPLICATION_JSON)
116     @ApiOperation(value = "Create Capability Type from yaml", httpMethod = "POST", notes = "Returns created Capability Type", response = Response.class)
117     @ApiResponses(value = { @ApiResponse(code = 201, message = "Capability Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
118     @ApiResponse(code = 409, message = "Capability Type already exist") })
119     public Response uploadCapabilityType(@ApiParam("FileInputStream") @FormDataParam("capabilityTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
120         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload));
121         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name());
122     }
123
124     @POST
125     @Path("/interfaceLifecycle")
126     @Consumes(MediaType.MULTIPART_FORM_DATA)
127     @Produces(MediaType.APPLICATION_JSON)
128     @ApiOperation(value = "Create Interface Lyfecycle Type from yaml", httpMethod = "POST", notes = "Returns created Interface Lifecycle Type", response = Response.class)
129     @ApiResponses(value = { @ApiResponse(code = 201, message = "Interface Lifecycle Type created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
130     @ApiResponse(code = 409, message = "Interface Lifecycle Type already exist") })
131     public Response uploadInterfaceLifecycleType(@ApiParam("FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
132         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload));
133         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types");
134     }
135
136     @POST
137     @Path("/categories")
138     @Consumes(MediaType.MULTIPART_FORM_DATA)
139     @Produces(MediaType.APPLICATION_JSON)
140     @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created categories", response = Response.class)
141     @ApiResponses(value = { @ApiResponse(code = 201, message = "Categories created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
142     @ApiResponse(code = 409, message = "Category already exist") })
143     public Response uploadCategories(@ApiParam("FileInputStream") @FormDataParam("categoriesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
144         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload));
145         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories");
146     }
147
148     @POST
149     @Path("/datatypes")
150     @Consumes(MediaType.MULTIPART_FORM_DATA)
151     @Produces(MediaType.APPLICATION_JSON)
152     @ApiOperation(value = "Create Categories from yaml", httpMethod = "POST", notes = "Returns created data types", response = Response.class)
153     @ApiResponses(value = { @ApiResponse(code = 201, message = "Data types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
154     @ApiResponse(code = 409, message = "Data types already exist") })
155     public Response uploadDataTypes(@ApiParam("FileInputStream") @FormDataParam("dataTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
156         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createDataTypes(responseWrapper, ymlPayload);
157         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.DataType.getName());
158     }
159
160     @POST
161     @Path("/grouptypes")
162     @Consumes(MediaType.MULTIPART_FORM_DATA)
163     @Produces(MediaType.APPLICATION_JSON)
164     @ApiOperation(value = "Create GroupTypes from yaml", httpMethod = "POST", notes = "Returns created group types", response = Response.class)
165     @ApiResponses(value = { @ApiResponse(code = 201, message = "group types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
166     @ApiResponse(code = 409, message = "group types already exist") })
167     public Response uploadGroupTypes(@ApiParam("FileInputStream") @FormDataParam("groupTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
168         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) -> createGroupTypes(responseWrapper, ymlPayload);
169         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.GroupType.getName());
170     }
171
172     @POST
173     @Path("/policytypes")
174     @Consumes(MediaType.MULTIPART_FORM_DATA)
175     @Produces(MediaType.APPLICATION_JSON)
176     @ApiOperation(value = "Create PolicyTypes from yaml", httpMethod = "POST", notes = "Returns created policy types", response = Response.class)
177     @ApiResponses(value = { @ApiResponse(code = 201, message = "policy types created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
178     @ApiResponse(code = 409, message = "policy types already exist") })
179     public Response uploadPolicyTypes(@ApiParam("FileInputStream") @FormDataParam("policyTypesZip") File file, @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
180         return uploadElementTypeServletLogic(this::createPolicyTypes, file, request, creator, NodeTypeEnum.PolicyType.getName());
181     }
182
183     private Response uploadElementTypeServletLogic(ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod, File file, final HttpServletRequest request, String creator, String elementTypeName) {
184         init(log);
185         String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
186         try {
187             Wrapper<Response> responseWrapper = new Wrapper<>();
188             Wrapper<User> userWrapper = new Wrapper<>();
189             Wrapper<String> yamlStringWrapper = new Wrapper<>();
190
191             String url = request.getMethod() + " " + request.getRequestURI();
192             log.debug("Start handle request of {}", url);
193
194             validateUserExist(responseWrapper, userWrapper, userId);
195
196             if (responseWrapper.isEmpty()) {
197                 validateUserRole(responseWrapper, userWrapper.getInnerElement());
198             }
199
200             if (responseWrapper.isEmpty()) {
201                 validateDataNotNull(responseWrapper, file);
202             }
203
204             if (responseWrapper.isEmpty()) {
205                 fillZipContents(yamlStringWrapper, file);
206             }
207
208             if (responseWrapper.isEmpty()) {
209                 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement());
210             }
211
212             return responseWrapper.getInnerElement();
213
214         } catch (Exception e) {
215             log.debug("create {} failed with exception:", elementTypeName, e);
216             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create " + elementTypeName);
217             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
218         }
219     }
220
221     private <T> void createElementsType(Wrapper<Response> responseWrapper, Supplier<Either<T, ResponseFormat>> elementsCreater) {
222         Either<T, ResponseFormat> eitherResult = elementsCreater.get();
223         if (eitherResult.isRight()) {
224             Response response = buildErrorResponse(eitherResult.right().value());
225             responseWrapper.setInnerElement(response);
226         } else {
227             try {
228                 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), RepresentationUtils.toRepresentation(eitherResult.left().value()));
229                 responseWrapper.setInnerElement(response);
230             } catch (Exception e) {
231                 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
232                 responseWrapper.setInnerElement(response);
233                 log.error("#createElementsType - json serialization failed with error: ", e);
234             }
235         }
236     }
237
238     // data types
239     private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml) {
240         final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> dataTypeImportManager.createDataTypes(dataTypesYml);
241         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.DATA_TYPE_ALREADY_EXIST, NodeTypeEnum.DataType.name());
242     }
243
244     // group types
245     private void createGroupTypes(Wrapper<Response> responseWrapper, String groupTypesYml) {
246         final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> groupTypeImportManager.createGroupTypes(groupTypesYml);
247         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.GROUP_TYPE_ALREADY_EXIST, NodeTypeEnum.GroupType.name());
248     }
249
250     // policy types
251     private void createPolicyTypes(Wrapper<Response> responseWrapper, String policyTypesYml) {
252         final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> policyTypeImportManager.createPolicyTypes(policyTypesYml);
253         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.POLICY_TYPE_ALREADY_EXIST, NodeTypeEnum.PolicyType.name());
254     }
255
256     // data types
257     private <ElementTypeDefinition> void buildStatusForElementTypeCreate(Wrapper<Response> responseWrapper, Supplier<Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml, ActionStatus alreadyExistStatus, String elementTypeName) {
258         Either<List<ImmutablePair<ElementTypeDefinition, Boolean>>, ResponseFormat> eitherResult = generateElementTypeFromYml.get();
259
260         if (eitherResult.isRight()) {
261             Response response = buildErrorResponse(eitherResult.right().value());
262             responseWrapper.setInnerElement(response);
263         } else {
264             Object representation;
265             try {
266                 List<ImmutablePair<ElementTypeDefinition, Boolean>> list = eitherResult.left().value();
267                 ActionStatus status = ActionStatus.OK;
268                 if (list != null) {
269
270                     // Group result by the right value - true or false.
271                     // I.e., get the number of data types which are new and
272                     // which are old.
273                     Map<Boolean, List<ImmutablePair<ElementTypeDefinition, Boolean>>> collect = list.stream().collect(Collectors.groupingBy(ImmutablePair<ElementTypeDefinition, Boolean>::getRight));
274                     if (collect != null) {
275                         Set<Boolean> keySet = collect.keySet();
276                         if (keySet.size() == 1) {
277                             Boolean isNew = keySet.iterator().next();
278                             if (isNew.booleanValue()) {
279                                 // all data types created at the first time
280                                 status = ActionStatus.CREATED;
281                             } else {
282                                 // All data types already exists
283
284                                 status = alreadyExistStatus;
285                             }
286                         }
287                     }
288                 }
289                 representation = RepresentationUtils.toRepresentation(eitherResult.left().value());
290
291                 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(status), representation);
292                 responseWrapper.setInnerElement(response);
293
294             } catch (IOException e) {
295                 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create " + elementTypeName);
296                 log.debug("failed to convert {} to json", elementTypeName, e);
297                 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
298                 responseWrapper.setInnerElement(response);
299             }
300         }
301     }
302
303 }