2 * Copyright © 2016-2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.openecomp.sdc.be.servlets;
18 import com.jcabi.aspects.Loggable;
19 import fj.data.Either;
20 import io.swagger.v3.oas.annotations.Operation;
21 import io.swagger.v3.oas.annotations.Parameter;
22 import io.swagger.v3.oas.annotations.media.ArraySchema;
23 import io.swagger.v3.oas.annotations.media.Content;
24 import io.swagger.v3.oas.annotations.media.Schema;
25 import io.swagger.v3.oas.annotations.responses.ApiResponse;
26 import io.swagger.v3.oas.annotations.servers.Server;
27 import io.swagger.v3.oas.annotations.tags.Tag;
28 import java.util.List;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.ws.rs.Consumes;
34 import javax.ws.rs.DELETE;
35 import javax.ws.rs.GET;
36 import javax.ws.rs.HeaderParam;
37 import javax.ws.rs.POST;
38 import javax.ws.rs.PUT;
39 import javax.ws.rs.Path;
40 import javax.ws.rs.PathParam;
41 import javax.ws.rs.Produces;
42 import javax.ws.rs.core.Context;
43 import javax.ws.rs.core.MediaType;
44 import javax.ws.rs.core.Response;
45 import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic;
46 import org.openecomp.sdc.be.config.BeEcompErrorManager;
47 import org.openecomp.sdc.be.dao.api.ActionStatus;
48 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
49 import org.openecomp.sdc.be.impl.ComponentsUtils;
50 import org.openecomp.sdc.be.model.PropertyDefinition;
51 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
52 import org.openecomp.sdc.be.resources.data.EntryData;
53 import org.openecomp.sdc.common.api.Constants;
54 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
55 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
56 import org.openecomp.sdc.common.log.enums.StatusCode;
57 import org.openecomp.sdc.exception.ResponseFormat;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
63 @Tag(name = "SDCE-2 APIs")
64 @Server(url = "/sdc2/rest")
66 public class ComponentPropertyServlet extends BeGenericServlet {
68 private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class);
69 private static final String CREATE_PROPERTY = "Create Property";
70 private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}";
71 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ComponentPropertyServlet.class.getName());
72 private final PropertyBusinessLogic propertyBusinessLogic;
73 private final ApplicationDataTypeCache applicationDataTypeCache;
76 public ComponentPropertyServlet(ComponentsUtils componentsUtils,
77 ApplicationDataTypeCache applicationDataTypeCache, PropertyBusinessLogic propertyBusinessLogic) {
78 super(componentsUtils);
79 this.applicationDataTypeCache = applicationDataTypeCache;
80 this.propertyBusinessLogic = propertyBusinessLogic;
84 @Path("services/{serviceId}/properties")
85 @Consumes(MediaType.APPLICATION_JSON)
86 @Produces(MediaType.APPLICATION_JSON)
87 @Operation(description = "Create Service Property", method = "POST", summary = "Returns created service property", responses = {
88 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
89 @ApiResponse(responseCode = "201", description = "Service property created"),
90 @ApiResponse(responseCode = "403", description = "Restricted operation"),
91 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
92 @ApiResponse(responseCode = "409", description = "Service property already exist")})
93 public Response createPropertyInService(
94 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
95 @Parameter(description = "Service property to be created", required = true) String data, @Context final HttpServletRequest request,
96 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
97 return createProperty(serviceId, data, request, userId);
101 @Path("resources/{resourceId}/properties")
102 @Consumes(MediaType.APPLICATION_JSON)
103 @Produces(MediaType.APPLICATION_JSON)
104 @Operation(description = "Create Resource Property", method = "POST", summary = "Returns created service property", responses = {
105 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
106 @ApiResponse(responseCode = "201", description = "Resource property created"),
107 @ApiResponse(responseCode = "403", description = "Restricted operation"),
108 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
109 @ApiResponse(responseCode = "409", description = "Resource property already exist")})
110 public Response createPropertyInResource(
111 @Parameter(description = "Resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
112 @Parameter(description = "Resource property to be created", required = true) String data, @Context final HttpServletRequest request,
113 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
114 return createProperty(resourceId, data, request, userId);
118 @Path("services/{serviceId}/properties/{propertyId}")
119 @Consumes(MediaType.APPLICATION_JSON)
120 @Produces(MediaType.APPLICATION_JSON)
121 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property of service", responses = {
122 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
123 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
124 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
125 @ApiResponse(responseCode = "404", description = "Service property not found")})
126 public Response getPropertyInService(
127 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
128 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
129 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
130 return getProperty(serviceId, propertyId, request, userId);
134 @Path("resources/{resourceId}/properties/{propertyId}")
135 @Consumes(MediaType.APPLICATION_JSON)
136 @Produces(MediaType.APPLICATION_JSON)
137 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property of resource", responses = {
138 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
139 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
140 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
141 @ApiResponse(responseCode = "404", description = "Resource property not found")})
142 public Response getPropertyInResource(
143 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
144 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
145 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
146 return getProperty(resourceId, propertyId, request, userId);
150 @Path("services/{serviceId}/properties")
151 @Consumes(MediaType.APPLICATION_JSON)
152 @Produces(MediaType.APPLICATION_JSON)
153 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property list of service", responses = {
154 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
155 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
156 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
157 @ApiResponse(responseCode = "404", description = "Service property not found")})
158 public Response getPropertyListInService(
159 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
160 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
161 return getPropertyList(serviceId, request, userId);
165 @Path("resources/{resourceId}/properties")
166 @Consumes(MediaType.APPLICATION_JSON)
167 @Produces(MediaType.APPLICATION_JSON)
168 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property list of resource", responses = {
169 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
170 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
171 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
172 @ApiResponse(responseCode = "404", description = "Resource property not found")})
173 public Response getPropertyListInResource(
174 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
175 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
176 return getPropertyList(resourceId, request, userId);
180 @Path("services/{serviceId}/properties/{propertyId}")
181 @Consumes(MediaType.APPLICATION_JSON)
182 @Produces(MediaType.APPLICATION_JSON)
183 @Operation(description = "Delete Service Property", method = "DELETE", summary = "Returns deleted property", responses = {
184 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
185 @ApiResponse(responseCode = "204", description = "deleted property"),
186 @ApiResponse(responseCode = "403", description = "Restricted operation"),
187 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
188 @ApiResponse(responseCode = "404", description = "Service property not found")})
189 public Response deletePropertyInService(
190 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
191 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
192 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
193 return deleteProperty(serviceId, propertyId, request, userId);
197 @Path("resources/{resourceId}/properties/{propertyId}")
198 @Consumes(MediaType.APPLICATION_JSON)
199 @Produces(MediaType.APPLICATION_JSON)
200 @Operation(description = "Delete Resource Property", method = "DELETE", summary = "Returns deleted property", responses = {
201 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
202 @ApiResponse(responseCode = "204", description = "deleted property"),
203 @ApiResponse(responseCode = "403", description = "Restricted operation"),
204 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
205 @ApiResponse(responseCode = "404", description = "Resource property not found")})
206 public Response deletePropertyInResource(
207 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
208 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
209 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
210 return deleteProperty(resourceId, propertyId, request, userId);
214 @Path("services/{serviceId}/properties")
215 @Consumes(MediaType.APPLICATION_JSON)
216 @Produces(MediaType.APPLICATION_JSON)
217 @Operation(description = "Update Service Property", method = "PUT", summary = "Returns updated property", responses = {
218 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
219 @ApiResponse(responseCode = "200", description = "Service property updated"),
220 @ApiResponse(responseCode = "403", description = "Restricted operation"),
221 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
222 public Response updatePropertyInService(
223 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
224 @Parameter(description = "Service property to update", required = true) String data, @Context final HttpServletRequest request,
225 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
226 return updateProperty(serviceId, data, request, userId);
230 @Path("resources/{resourceId}/properties")
231 @Consumes(MediaType.APPLICATION_JSON)
232 @Produces(MediaType.APPLICATION_JSON)
233 @Operation(description = "Update Resource Property", method = "PUT", summary = "Returns updated property", responses = {
234 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
235 @ApiResponse(responseCode = "200", description = "Resource property updated"),
236 @ApiResponse(responseCode = "403", description = "Restricted operation"),
237 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
238 public Response updatePropertyInResource(
239 @Parameter(description = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
240 @Parameter(description = "Resource property to update", required = true) String data, @Context final HttpServletRequest request,
241 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
242 return updateProperty(resourceId, data, request, userId);
245 private Response createProperty(String componentId, String data, HttpServletRequest request, String userId) {
246 String url = request.getMethod() + " " + request.getRequestURI();
247 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
248 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.STARTED, "CREATE_PROPERTIES by user {} ", userId);
250 Either<Map<String, PropertyDefinition>, ActionStatus> propertyDefinition = getPropertyModel(componentId, data);
251 if (propertyDefinition.isRight()) {
252 return buildErrorResponse(getComponentsUtils().getResponseFormat(propertyDefinition.right().value()));
254 Map<String, PropertyDefinition> properties = propertyDefinition.left().value();
255 if (properties == null || properties.size() != 1) {
256 log.info("Property content is invalid - {}", data);
257 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
260 //Validate value and Constraint of property and Fetch all data types from cache
261 Either<Boolean, ResponseFormat> constraintValidatorResponse = new PropertyValueConstraintValidationUtil()
262 .validatePropertyConstraints(properties.values(), applicationDataTypeCache,
263 propertyBusinessLogic.getComponentModelByComponentId(componentId));
264 if (constraintValidatorResponse.isRight()) {
265 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
266 return buildErrorResponse(constraintValidatorResponse.right().value());
269 Map.Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
270 PropertyDefinition newPropertyDefinition = entry.getValue();
271 newPropertyDefinition.setParentUniqueId(componentId);
272 newPropertyDefinition.setUserCreated(true);
273 Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyEither =
274 propertyBusinessLogic.addPropertyToComponent(componentId, newPropertyDefinition, userId);
275 if (addPropertyEither.isRight()) {
276 return buildErrorResponse(addPropertyEither.right().value());
278 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.COMPLETE, "CREATE_PROPERTIES by user {} ", userId);
279 return buildOkResponse(newPropertyDefinition);
280 } catch (Exception e) {
281 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
282 log.debug("create property failed with exception", e);
283 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
287 private Response updateProperty(String componentId, String data, HttpServletRequest request, String userId) {
288 String url = request.getMethod() + " " + request.getRequestURI();
289 log.debug("Start handle request of {}", url);
290 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED, "UPDATE_PROPERTIES by user {} ", userId);
291 log.debug("modifier id is {}", userId);
294 // convert json to PropertyDefinition
295 Either<Map<String, PropertyDefinition>, ActionStatus> propertiesListEither = getPropertiesListForUpdate(data);
296 if (propertiesListEither.isRight()) {
297 return buildErrorResponse(getComponentsUtils().getResponseFormat(propertiesListEither.right().value()));
299 Map<String, PropertyDefinition> properties = propertiesListEither.left().value();
300 if (properties == null) {
301 log.info("Property content is invalid - {}", data);
302 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
304 //Validate value and Constraint of property and Fetch all data types from cache
305 Either<Boolean, ResponseFormat> constraintValidatorResponse = new PropertyValueConstraintValidationUtil()
306 .validatePropertyConstraints(properties.values(), applicationDataTypeCache,
307 propertyBusinessLogic.getComponentModelByComponentId(componentId));
308 if (constraintValidatorResponse.isRight()) {
309 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
310 return buildErrorResponse(constraintValidatorResponse.right().value());
313 for (PropertyDefinition propertyDefinition : properties.values()) {
314 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
315 .updateComponentProperty(componentId, propertyDefinition.getUniqueId(), propertyDefinition, userId);
316 if (status.isRight()) {
317 log.info("Failed to update Property. Reason - {}", status.right().value());
318 return buildErrorResponse(status.right().value());
320 log.debug("Property id {} updated successfully ", status.left().value().getValue().getUniqueId());
322 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "UPDATE_PROPERTIES by user {} ", userId);
323 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties);
324 } catch (Exception e) {
325 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
326 log.debug("update property failed with exception", e);
327 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
331 private Response getProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
332 String url = request.getMethod() + " " + request.getRequestURI();
333 log.debug(DEBUG_MESSAGE, url, userId);
335 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> retrievedPropertyEither = propertyBusinessLogic
336 .getComponentProperty(componentId, propertyId, userId);
337 if (retrievedPropertyEither.isRight()) {
338 return buildErrorResponse(retrievedPropertyEither.right().value());
340 return buildOkResponse(retrievedPropertyEither.left().value());
341 } catch (Exception e) {
342 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
343 log.debug("get property failed with exception", e);
344 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
348 private Response getPropertyList(String componentId, HttpServletRequest request, String userId) {
349 String url = request.getMethod() + " " + request.getRequestURI();
350 log.debug(DEBUG_MESSAGE, url, userId);
352 Either<List<PropertyDefinition>, ResponseFormat> propertiesListEither = propertyBusinessLogic.getPropertiesList(componentId, userId);
353 if (propertiesListEither.isRight()) {
354 return buildErrorResponse(propertiesListEither.right().value());
356 return buildOkResponse(propertiesListEither.left().value());
357 } catch (Exception e) {
358 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
359 log.debug("get property failed with exception", e);
360 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
364 private Response deleteProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
365 String url = request.getMethod() + " " + request.getRequestURI();
366 log.debug(DEBUG_MESSAGE, url, userId);
368 // delete the property
369 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
370 .deletePropertyFromComponent(componentId, propertyId, userId);
371 if (status.isRight()) {
372 log.debug("Failed to delete Property. Reason - ", status.right().value());
373 return buildErrorResponse(status.right().value());
375 Map.Entry<String, PropertyDefinition> property = status.left().value();
376 log.debug("Property {} deleted successfully with id {}", property.getKey(), property.getValue().getUniqueId());
377 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), propertyToJson(property));
378 } catch (Exception e) {
379 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
380 log.debug("delete property failed with exception", e);
381 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));