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.
17 package org.openecomp.sdc.be.servlets;
19 import com.jcabi.aspects.Loggable;
20 import fj.data.Either;
21 import io.swagger.v3.oas.annotations.Operation;
22 import io.swagger.v3.oas.annotations.Parameter;
23 import io.swagger.v3.oas.annotations.media.ArraySchema;
24 import io.swagger.v3.oas.annotations.media.Content;
25 import io.swagger.v3.oas.annotations.media.Schema;
26 import io.swagger.v3.oas.annotations.responses.ApiResponse;
27 import io.swagger.v3.oas.annotations.servers.Server;
28 import io.swagger.v3.oas.annotations.servers.Servers;
29 import io.swagger.v3.oas.annotations.tags.Tag;
30 import io.swagger.v3.oas.annotations.tags.Tags;
31 import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic;
32 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
33 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
34 import org.openecomp.sdc.be.config.BeEcompErrorManager;
35 import org.openecomp.sdc.be.dao.api.ActionStatus;
36 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
37 import org.openecomp.sdc.be.impl.ComponentsUtils;
38 import org.openecomp.sdc.be.model.PropertyDefinition;
39 import org.openecomp.sdc.be.model.User;
40 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
41 import org.openecomp.sdc.be.resources.data.EntryData;
42 import org.openecomp.sdc.be.user.UserBusinessLogic;
43 import org.openecomp.sdc.common.api.Constants;
44 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
45 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
46 import org.openecomp.sdc.common.log.enums.StatusCode;
47 import org.openecomp.sdc.exception.ResponseFormat;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 import javax.inject.Inject;
52 import javax.inject.Singleton;
53 import javax.servlet.http.HttpServletRequest;
54 import javax.ws.rs.Consumes;
55 import javax.ws.rs.DELETE;
56 import javax.ws.rs.GET;
57 import javax.ws.rs.HeaderParam;
58 import javax.ws.rs.POST;
59 import javax.ws.rs.PUT;
60 import javax.ws.rs.Path;
61 import javax.ws.rs.PathParam;
62 import javax.ws.rs.Produces;
63 import javax.ws.rs.core.Context;
64 import javax.ws.rs.core.MediaType;
65 import javax.ws.rs.core.Response;
66 import java.util.List;
69 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
71 @Tags({@Tag(name = "SDC Internal APIs")})
72 @Servers({@Server(url = "/sdc2/rest")})
74 public class ComponentPropertyServlet extends BeGenericServlet {
76 private final PropertyBusinessLogic propertyBusinessLogic;
77 private final ApplicationDataTypeCache applicationDataTypeCache;
80 public ComponentPropertyServlet(UserBusinessLogic userBusinessLogic,
81 ComponentsUtils componentsUtils,
82 ApplicationDataTypeCache applicationDataTypeCache,
83 PropertyBusinessLogic propertyBusinessLogic) {
84 super(userBusinessLogic, componentsUtils);
85 this.applicationDataTypeCache = applicationDataTypeCache;
86 this.propertyBusinessLogic = propertyBusinessLogic;
89 private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class);
90 private static final String CREATE_PROPERTY = "Create Property";
91 private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}";
92 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ComponentPropertyServlet.class.getName());
96 @Path("services/{serviceId}/properties")
97 @Consumes(MediaType.APPLICATION_JSON)
98 @Produces(MediaType.APPLICATION_JSON)
99 @Operation(description = "Create Service Property", method = "POST", summary = "Returns created service property",
100 responses = {@ApiResponse(
101 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
102 @ApiResponse(responseCode = "201", description = "Service property created"),
103 @ApiResponse(responseCode = "403", description = "Restricted operation"),
104 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
105 @ApiResponse(responseCode = "409", description = "Service property already exist")})
106 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
107 public Response createPropertyInService(
108 @Parameter(description = "service id to update with new property",
109 required = true) @PathParam("serviceId") final String serviceId,
110 @Parameter(description = "Service property to be created", required = true) String data,
111 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
113 return createProperty(serviceId, data, request, userId);
117 @Path("resources/{resourceId}/properties")
118 @Consumes(MediaType.APPLICATION_JSON)
119 @Produces(MediaType.APPLICATION_JSON)
120 @Operation(description = "Create Resource Property", method = "POST", summary = "Returns created service property",
121 responses = {@ApiResponse(
122 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
123 @ApiResponse(responseCode = "201", description = "Resource property created"),
124 @ApiResponse(responseCode = "403", description = "Restricted operation"),
125 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
126 @ApiResponse(responseCode = "409", description = "Resource property already exist")})
127 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
128 public Response createPropertyInResource(
129 @Parameter(description = "Resource id to update with new property",
130 required = true) @PathParam("resourceId") final String resourceId,
131 @Parameter(description = "Resource property to be created", required = true) String data,
132 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
134 return createProperty(resourceId, data, request, userId);
139 @Path("services/{serviceId}/properties/{propertyId}")
140 @Consumes(MediaType.APPLICATION_JSON)
141 @Produces(MediaType.APPLICATION_JSON)
142 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property of service",
143 responses = {@ApiResponse(
144 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
145 @ApiResponse(responseCode = "200", description = "property"),
146 @ApiResponse(responseCode = "403", description = "Restricted operation"),
147 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
148 @ApiResponse(responseCode = "404", description = "Service property not found")})
149 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
150 public Response getPropertyInService(
151 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
152 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
153 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
155 return getProperty(serviceId, propertyId, request, userId);
159 @Path("resources/{resourceId}/properties/{propertyId}")
160 @Consumes(MediaType.APPLICATION_JSON)
161 @Produces(MediaType.APPLICATION_JSON)
162 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property of resource",
163 responses = {@ApiResponse(
164 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
165 @ApiResponse(responseCode = "200", description = "property"),
166 @ApiResponse(responseCode = "403", description = "Restricted operation"),
167 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
168 @ApiResponse(responseCode = "404", description = "Resource property not found")})
169 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
170 public Response getPropertyInResource(
171 @Parameter(description = "resource id of property",
172 required = true) @PathParam("resourceId") final String resourceId,
173 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
174 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
176 return getProperty(resourceId, propertyId, request, userId);
180 @Path("services/{serviceId}/properties")
181 @Consumes(MediaType.APPLICATION_JSON)
182 @Produces(MediaType.APPLICATION_JSON)
183 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property list of service",
184 responses = {@ApiResponse(
185 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
186 @ApiResponse(responseCode = "200", description = "property"),
187 @ApiResponse(responseCode = "403", description = "Restricted operation"),
188 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
189 @ApiResponse(responseCode = "404", description = "Service property not found")})
190 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
191 public Response getPropertyListInService(
192 @Parameter(description = "service id of property",
193 required = true) @PathParam("serviceId") final String serviceId,
194 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
196 return getPropertyList(serviceId, request, userId);
200 @Path("resources/{resourceId}/properties")
201 @Consumes(MediaType.APPLICATION_JSON)
202 @Produces(MediaType.APPLICATION_JSON)
203 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property list of resource",
204 responses = {@ApiResponse(
205 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
206 @ApiResponse(responseCode = "200", description = "property"),
207 @ApiResponse(responseCode = "403", description = "Restricted operation"),
208 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
209 @ApiResponse(responseCode = "404", description = "Resource property not found")})
210 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
211 public Response getPropertyListInResource(
212 @Parameter(description = "resource id of property",
213 required = true) @PathParam("resourceId") final String resourceId,
214 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
216 return getPropertyList(resourceId, request, userId);
220 @Path("services/{serviceId}/properties/{propertyId}")
221 @Consumes(MediaType.APPLICATION_JSON)
222 @Produces(MediaType.APPLICATION_JSON)
223 @Operation(description = "Delete Service Property", method = "DELETE", summary = "Returns deleted property",
224 responses = {@ApiResponse(
225 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
226 @ApiResponse(responseCode = "204", description = "deleted property"),
227 @ApiResponse(responseCode = "403", description = "Restricted operation"),
228 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
229 @ApiResponse(responseCode = "404", description = "Service property not found")})
230 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
231 public Response deletePropertyInService(
232 @Parameter(description = "service id of property",
233 required = true) @PathParam("serviceId") final String serviceId,
234 @Parameter(description = "Property id to delete",
235 required = true) @PathParam("propertyId") final String propertyId,
236 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
238 return deleteProperty(serviceId, propertyId, request, userId);
242 @Path("resources/{resourceId}/properties/{propertyId}")
243 @Consumes(MediaType.APPLICATION_JSON)
244 @Produces(MediaType.APPLICATION_JSON)
245 @Operation(description = "Delete Resource Property", method = "DELETE", summary = "Returns deleted property",
246 responses = {@ApiResponse(
247 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
248 @ApiResponse(responseCode = "204", description = "deleted property"),
249 @ApiResponse(responseCode = "403", description = "Restricted operation"),
250 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
251 @ApiResponse(responseCode = "404", description = "Resource property not found")})
252 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
253 public Response deletePropertyInResource(
254 @Parameter(description = "resource id of property",
255 required = true) @PathParam("resourceId") final String resourceId,
256 @Parameter(description = "Property id to delete",
257 required = true) @PathParam("propertyId") final String propertyId,
258 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
260 return deleteProperty(resourceId, propertyId, request, userId);
264 @Path("services/{serviceId}/properties")
265 @Consumes(MediaType.APPLICATION_JSON)
266 @Produces(MediaType.APPLICATION_JSON)
267 @Operation(description = "Update Service Property", method = "PUT", summary = "Returns updated property",
268 responses = {@ApiResponse(
269 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
270 @ApiResponse(responseCode = "200", description = "Service property updated"),
271 @ApiResponse(responseCode = "403", description = "Restricted operation"),
272 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
273 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
274 public Response updatePropertyInService(
275 @Parameter(description = "service id to update with new property",
276 required = true) @PathParam("serviceId") final String serviceId,
277 @Parameter(description = "Service property to update", required = true) String data,
278 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
280 return updateProperty(serviceId, data, request, userId);
284 @Path("resources/{resourceId}/properties")
285 @Consumes(MediaType.APPLICATION_JSON)
286 @Produces(MediaType.APPLICATION_JSON)
287 @Operation(description = "Update Resource Property", method = "PUT", summary = "Returns updated property",
288 responses = {@ApiResponse(
289 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
290 @ApiResponse(responseCode = "200", description = "Resource property updated"),
291 @ApiResponse(responseCode = "403", description = "Restricted operation"),
292 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
293 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
294 public Response updatePropertyInResource(
295 @Parameter(description = "resource id to update with new property",
296 required = true) @PathParam("resourceId") final String resourceId,
297 @Parameter(description = "Resource property to update", required = true) String data,
298 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
300 return updateProperty(resourceId, data, request, userId);
303 private Response createProperty(String componentId, String data, HttpServletRequest request,String userId) {
304 String url = request.getMethod() + " " + request.getRequestURI();
305 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
306 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.STARTED,"CREATE_PROPERTIES by user {} ", userId);
309 Either<Map<String, PropertyDefinition>, ActionStatus> propertyDefinition =
310 getPropertyModel(componentId, data);
311 if (propertyDefinition.isRight()) {
312 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(propertyDefinition.right().value());
313 return buildErrorResponse(responseFormat);
316 Map<String, PropertyDefinition> properties = propertyDefinition.left().value();
317 if (properties == null || properties.size() != 1) {
318 log.info("Property content is invalid - {}", data);
319 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
320 return buildErrorResponse(responseFormat);
323 Map.Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
324 PropertyDefinition newPropertyDefinition = entry.getValue();
325 newPropertyDefinition.setParentUniqueId(componentId);
326 String propertyName = newPropertyDefinition.getName();
328 Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyEither =
329 propertyBusinessLogic.addPropertyToComponent(componentId, propertyName, newPropertyDefinition, userId);
331 if(addPropertyEither.isRight()) {
332 return buildErrorResponse(addPropertyEither.right().value());
335 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.COMPLETE,"CREATE_PROPERTIES by user {} ", userId);
336 return buildOkResponse(newPropertyDefinition);
338 } catch (Exception e) {
339 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
340 log.debug("create property failed with exception", e);
341 ResponseFormat responseFormat =
342 getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
343 return buildErrorResponse(responseFormat);
348 private Response updateProperty(String componentId, String data, HttpServletRequest request, String userId) {
349 String url = request.getMethod() + " " + request.getRequestURI();
350 log.debug("Start handle request of {}", url);
351 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED,"UPDATE_PROPERTIES by user {} ", userId);
354 User modifier = new User();
355 modifier.setUserId(userId);
356 log.debug("modifier id is {}", userId);
359 // convert json to PropertyDefinition
361 Either<Map<String, PropertyDefinition>, ActionStatus> propertiesListEither =
362 getPropertiesListForUpdate(data);
363 if (propertiesListEither.isRight()) {
364 ResponseFormat responseFormat =
365 getComponentsUtils().getResponseFormat(propertiesListEither.right().value());
366 return buildErrorResponse(responseFormat);
368 Map<String, PropertyDefinition> properties = propertiesListEither.left().value();
369 if (properties == null) {
370 log.info("Property content is invalid - {}", data);
371 ResponseFormat responseFormat =
372 getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
373 return buildErrorResponse(responseFormat);
376 //Validate value and Constraint of property
377 Either<Boolean, ResponseFormat> constraintValidatorResponse =
378 PropertyValueConstraintValidationUtil.getInstance().
379 validatePropertyConstraints(properties.values(), applicationDataTypeCache);
380 if (constraintValidatorResponse.isRight()) {
381 log.error("Failed validation value and constraint of property: {}",
382 constraintValidatorResponse.right().value());
383 return buildErrorResponse(constraintValidatorResponse.right().value());
388 for(PropertyDefinition propertyDefinition : properties.values()) {
389 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status =
390 propertyBusinessLogic.updateComponentProperty(
391 componentId, propertyDefinition.getUniqueId(), propertyDefinition, userId);
392 if (status.isRight()) {
393 log.info("Failed to update Property. Reason - ", status.right().value());
394 return buildErrorResponse(status.right().value());
396 EntryData<String, PropertyDefinition> property = status.left().value();
397 PropertyDefinition updatedPropertyDefinition = property.getValue();
399 log.debug("Property id {} updated successfully ", updatedPropertyDefinition.getUniqueId());
402 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
403 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE,"UPDATE_PROPERTIES by user {} ", userId);
404 return buildOkResponse(responseFormat, properties);
406 } catch (Exception e) {
407 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
408 log.debug("update property failed with exception", e);
409 ResponseFormat responseFormat =
410 getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
411 return buildErrorResponse(responseFormat);
416 private Response getProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
417 String url = request.getMethod() + " " + request.getRequestURI();
418 log.debug(DEBUG_MESSAGE, url, userId);
421 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> retrievedPropertyEither =
422 propertyBusinessLogic.getComponentProperty(componentId, propertyId, userId);
424 if(retrievedPropertyEither.isRight()) {
425 return buildErrorResponse(retrievedPropertyEither.right().value());
428 return buildOkResponse(retrievedPropertyEither.left().value());
430 } catch (Exception e) {
431 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
432 log.debug("get property failed with exception", e);
433 ResponseFormat responseFormat =
434 getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
435 return buildErrorResponse(responseFormat);
438 private Response getPropertyList(String componentId, HttpServletRequest request, String userId) {
440 String url = request.getMethod() + " " + request.getRequestURI();
441 log.debug(DEBUG_MESSAGE, url, userId);
444 Either<List<PropertyDefinition>, ResponseFormat> propertiesListEither =
445 propertyBusinessLogic.getPropertiesList(componentId, userId);
447 if(propertiesListEither.isRight()) {
448 return buildErrorResponse(propertiesListEither.right().value());
451 return buildOkResponse(propertiesListEither.left().value());
453 } catch (Exception e) {
454 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
455 log.debug("get property failed with exception", e);
456 ResponseFormat responseFormat =
457 getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
458 return buildErrorResponse(responseFormat);
461 private Response deleteProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
462 String url = request.getMethod() + " " + request.getRequestURI();
463 log.debug(DEBUG_MESSAGE, url, userId);
467 // delete the property
468 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> status =
469 propertyBusinessLogic.deletePropertyFromComponent(componentId, propertyId, userId);
470 if (status.isRight()) {
471 log.debug("Failed to delete Property. Reason - ", status.right().value());
472 return buildErrorResponse(status.right().value());
474 Map.Entry<String, PropertyDefinition> property = status.left().value();
475 String name = property.getKey();
476 PropertyDefinition propertyDefinition = property.getValue();
478 log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId());
479 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT);
480 return buildOkResponse(responseFormat, propertyToJson(property));
482 } catch (Exception e) {
483 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
484 log.debug("delete property failed with exception", e);
485 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
486 return buildErrorResponse(responseFormat);